算法很美(一)---位运算

一、找出数组中落单的那个数:

一个数组中,除了某一个数只出现了一次外,其他的数都出现了两次(只出现两次),请编写一个程序,不用辅助空间,遍历一次数组,找出这个数

思路:用到了相同数之间进行异或为0,不同数之间异或为1的结论,使所有数组中的数依次异或一次就好

public class Hello {
    
    
    public static void main(String[] args) {
    
    
        int arr [] = new int [11];
        for(int i = 0;i<5;i++){
    
    
            arr[i] = i;
            arr[i+5] = i;
        }
        arr[10] = 6;//这个数是落单的,问怎么找出这个数
        int a = arr[10];
        for(int i = 0;i<10;i++){
    
    
            a = a ^ arr[i];
        }
        System.out.println(a);
    }
}

二、一个数的二进制有多少个1呢?

思路:
1.可以采用之前的移位操作,将32位都移1一次,来与1进行异或,结果为1即表示该位上是1,然后将这个数字统计下,即为1的个数
2.将一个数减一,则从右到左第一个为1的二进制位上的1为0,而右边的0会变成1,再与自己做&运算,就会使右边的二进制位上的数及当前位上的数全变为0,依次进行,直到该数字等于0,记下运算次数,即为1的个数

public class Hello {
    
    
    public static void main(String[] args) {
    
    
    //方法1
      int count = 0;
      int b = 335;//这个数的二进制有多少个1?
      int i = 0;
      for(i = 0;i<32;i++){
    
    
          if(((b>>>i)&1) == 1){
    
     //这是移位的操作
              count++;
          }
      }
        System.out.println(count);
      //方法2
        int count1 = 0;
        while(b!= 0){
    
    
            b = (b-1)&b; //用他减1根他自己取异或
            count1++;
        }
        System.out.println(count1);
    }

}
  • 一个整数(不包括负数)若是二进制的整数次方,那他二进制位上至多只有一个1。

三、将整数的奇偶位互换:

思路:将一个整数与二进制表示为(1010 1010…)的数和(0101 0101…)的数分别进行与运算,然后前者左移一位,后者右移一位,再进行异或运算便可得到结果

public class Hello {
    
    
    public static void main(String[] args) {
    
    
        //将整数的奇偶位互换
        int c = 6;
        int a = 0xaaaaaaaa;//写成十六进制形式 这是1010 1010 ... 1010
        int b = 0x55555555;//同理           这是0101 0101 ... 0101
        c = ((c&a)>>1)^((c&b)<<1);
        System.out.println(c);
    }

}

四、0-1之间浮点实数的二进制表示

  • 给定一个介于0-1之间的实数,如0.625,类型为double,打印他的二进制表示0.101,
  • 因为小数点后的二进制分别表示0.5,0.25,0.125…
  • 如果该数字无法精确地用32位以内的二进制表示则输出Error

思路:将这个数乘2,如果比1大,则该位上填1,然后将1减去,否则填0.

public class Hello {
    
    
    public static void main(String[] args) {
    
    
        double a = 0.625;
        int count = 0;
        double b;
        String two = "0.";
        while(count < 32){
    
     //超过位数就跳出并打印ERROR
            if((a * 2) >= 1){
    
      //即是上述操作
                a = a * 2 - 1;
                two += "1";
            }else {
    
    
                a = a * 2;
                two += "0";
            }
            if(a<=0){
    
    
                break;
            }
            count++;
        }
        if(count<32){
    
    
        System.out.println(two);
        }else{
    
    
            System.out.println("ERROR");
        }
    }

}

五、出现k次与出现一次

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

思路

  • k个相同的k进制数做不进位加法结果为0。
  • 先把数都变成k进制的(下面以k=3举例)
  • 再做不进位加法
  • 再将数字转回来
public class Hello {
    
    
    public static void main(String[] args) {
    
    
        int [] arr = {
    
    2,2,2,9,7,7,7,3,3,3,6,6,6,0,0,0};
        int len = arr.length;//计算整个数组的长度,以便开辟二维数组
        char [][] kRadix = new char[len][];//开辟二维数组存储3进制的形式
        int k = 3;//设定为3进制

        int maxlen = 0;//不知道每个数转成对应的三进制具体有多长
        //转成k进制字符数组,对于每个数字
        for(int i = 0;i<len;i++){
    
    
            kRadix[i] = new StringBuilder(Integer.toString(arr[i],k)).reverse().toString().toCharArray();
            if (kRadix[i].length > maxlen)
                maxlen = kRadix[i].length;//要最长的三进制,以便好进行不进位加法
        }
        int [] resArr = new int[maxlen];
        for(int i = 0;i<len;i++) {
    
    //每个数字都要进行
            for (int j = 0; j < maxlen; j++) {
    
    
                if (j >= kRadix[i].length)
                    resArr[j] += 0;//如果长了,那就加0啦
                else {
    
    
                    resArr[j] += (kRadix[i][j] - '0'); //从char转换成数字
                }
            }
        }
        int res = 0;
        for(int i = 0;i<maxlen;i++){
    
    
             res += (resArr[i] % k) * (int)(Math.pow(k,i));//3的多少次
        }
        System.out.println(res);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45911278/article/details/112781299