位运算练习

找出唯一成对的数

1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均只出现一次。每个数组元素只能访问一次,设计一个算法,将他找出来;不用辅助存储空间,能否设计一个算法实现?

解析:一个数和本身异或为0,任何数和0异或还是这个数。比如2和2异或为0,那么2和2和2异或就为2。

只要将1~1000全都异或,再异或上数组里的1000个数,结果就是要找的答案。因为要找的元素异或了3次,而其他数异或了2次。

 1  import java.util.Random;
 2  public class 唯一成对的数 {
 3      public static void main(String[] args) {
 4          int N=1001;
 5          int[] arr=new int[N];
 6          int len=arr.length;
 7          for(int i=0;i<len-1;i++)
 8          {
 9              arr[i]=i+1;
10          }
11          
12          //最后一个数,是随机数
13          arr[len-1]=new Random().nextInt(N-1)+1;
14          //随机下标
15          int index=new Random().nextInt(N);
16          
17          //交换随机下标的数和随机数
18          int temp=arr[index];
19          arr[index]=arr[len-1];
20          arr[len-1]=temp;
21          
22          for(int i=0;i<N;i++)
23              System.out.print(arr[i]+" ");
24          
25          System.out.println();
26          
27          int x1=0;
28          //先将x1与1~N-1异或
29          for(int i=1;i<=N-1;i++)
30              x1=(x1^i);
31          //再将x1与数组中各个数异或
32          for(int i=0;i<N;i++)
33              x1=(x1^arr[i]);
34          
35          System.out.println(x1);
36      }
37  }

 

找出落单的那个数

一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

解析:只需全部异或,异或的结果就是答案。因为成对的数都相互抵消了。

 

二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。

例:9的二进制表示为1001,有2位是1。

法一:将数字1每次左移一位(就是1<<i),并与N进行与运算,如果结果等于(1<<i),那么个数加1

 1  import java.util.Scanner;
 2  public class _1的个数 {
 3      public static void main(String[] args) {
 4          Scanner sc=new Scanner(System.in);
 5          int N=sc.nextInt();
 6          System.out.println(Integer.toString(N,2));
 7          int count=0;
 8          for(int i=0;i<32;i++)
 9          {
10              if((N&(1<<i))==(1<<i))
11              {
12                  count++;
13              }
14          }
15          
16          System.out.println(count);
17      }
18  }

法二:将N每次右移一位,并与1与运算,如果结果为1,则个数加1

法三:整数N,N=(N-1)&N就是将N的最右边的1消除。

  1 0 1 0 0

-1    1 0 0 1 1

&——————

  1 0 0 0 0

-1    0 1 1 1 1

&——————

  0 0 0 0 0

 1  import java.util.Scanner;
 2  public class _1的个数 {
 3      public static void main(String[] args) {
 4          Scanner sc=new Scanner(System.in);
 5          int N=sc.nextInt();
 6          System.out.println(Integer.toString(N,2));
 7          int count=0;
 8          
 9          while(N!=0)
10          {
11              N=(N-1)&N;
12              count++;
13          }
14          
15          System.out.println(count);
16      }
17  }

是不是2的整数次方

用一条语句判断一个整数是不是2的整数次方。

解析:上题的思路 if(N&(N-1)==0)

 

将整数的奇偶位互换

将一个整数二进制表示的奇偶位互换

例:9的二进制:1001,互换后为0110

解析:将这个数与...10101010进行与运算,将偶数位提取,再与...01010101进行与远算,将奇数位提取。最后将提取到的偶数位右移一位,奇数位左移一位,两者异或,即得到互换效果。

 1  public class 奇偶位互换 {
 2      public static void main(String[] args) {
 3          int a=9;
 4          int b=m(a);
 5          System.out.println(Integer.toString(a,2));
 6          System.out.println(Integer.toString(b,2));
 7      }
 8      
 9      public static int m(int i)
10      {
11          int ou=i&0xaaaaaaaa;//和1010 1010 1010 。。。做与运算取出偶数位
12          int ji=i&0x55555555;//和0101 0101 0101 。。。做与运算取出奇数位
13          return (ou>>1)^(ji<<1);
14      }
15  }

 

0~1间浮点实数的二进制表示

给定一个介于0和1之间的实数(如0.625),类型为double,打印它的二进制表示(0.101),如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”

 1  public class 二进制小数 {
 2      public static void main(String[] args) {
 3          double num=0.875;
 4          StringBuilder sb=new StringBuilder("0.");
 5          while(num>0)
 6          {
 7              double r=num*2;
 8              if(r>=1)
 9              {
10                  sb.append("1");
11                  num=r-1;
12              }
13              else
14              {
15                  sb.append("0");
16                  num=r;
17              }
18              if(sb.length()>34)
19              {
20                  System.out.println("ERROR");
21                  return;
22              }
23          }
24          System.out.println(sb.toString());
25      }
26  }

 

出现k次与出现1次

数组中只有一个数出现了1次,其他的数都出现了k次,请输出出现了1次的数。

解析:

  2个相同的2进制数做不进位加法,结果为0

  10个相同的10进制数做不进位加法,结果为0

  k个相同的k进制数做不进位加法,结果为0

只要把所有数转为k进制,做一次不进位加法把它们都加起来,那么出现k次的数加完都会变为0,最终结果就是出现了1次的那个数。

 1 public class 出现k次 {
 2     public static void main(String[] args) {
 3         int[] arr= {2,2,2,9,7,7,7,3,3,3,6,6,6,0,0,0};
 4         int len=arr.length;
 5         char[][] kRadix=new char[len][];//k进制字符数组
 6         int k=3;
 7         //转成k进制字符数组
 8         int maxLen=0;
 9         for(int i=0;i<len;i++)
10         {
11             kRadix[i]=new StringBuilder(Integer.toString(arr[i],k))
12                                         .reverse().toString().toCharArray();
13             //记录最长的数组长度
14             if(kRadix[i].length>maxLen)
15                 maxLen=kRadix[i].length;
16             
17         }
18         
19         int[] resArr=new int[maxLen];//结果
20         for(int i=0;i<len;i++)
21         {
22             //不进位加法
23             for(int j=0;j<maxLen;j++)
24             {
25                 if(j>=kRadix[i].length)
26                     resArr[j]+=0;
27                 else
28                     resArr[j]+=(kRadix[i][j]-'0');
29             }
30         }
31         
32         //k进制转10进制
33         int res=0;
34         for(int i=0;i<maxLen;i++)
35         {
36             //每一位模k,再乘这一位的权重得到10进制
37             res+=(resArr[i]%k)*(int)(Math.pow(k,i));
38         }
39         System.out.println(res);
40     }
41 }

 

参考:《算法很美》

 

posted @ 2021-08-27 10:14  sxkio  阅读(94)  评论(0编辑  收藏  举报