剑指offer——(7)二进制中1的个数&&数组中只出现一次的两个数字

版权声明:本文自由转载,转载请注明出处。 https://blog.csdn.net/qq_38071429/article/details/83928795

位操作符简单记忆:

  • &(与):相同位同为1时结果为1 否则为0
  • |(或):相同位同为0时结果为0 否则为1
  • ^(异或):相同位相同结果为0 不同为1
  • ~(取反):0变成1 1变成0
  • m>>(右移)n:m的各二进位全部右移n位,低位丢弃,高位补0 ;m除与2的n次方。 
  • m<<(左移)n:m的各二进位全部左移n位,高位丢弃,低位补0 ;m乘与2的n次方。 

public class Solution {
     /*
      * 0x7FFFFFFF代表16进制表示的32位int型(4个字节)的最大值
      * 转化为二进制为:0111 1111 1111 1111 1111 1111 1111 1111
      * 最高位表示符号位(0为正,1为负)
      * 位运算符'&'的含义:以二进制形式比较 相同位同为1则为1 否则为0
      * 举2个例子(用4位举例):
      *          1&2 -> 0001 & 0010 -> 0000
      *          2&3 -> 0010 & 0011 -> 0010    
      * 如果一个数小于0 和0x7FFFFFFF进行&操作符运算 这个数会变成正数
      * 举个例子(用8位举例):
      * -1的二进制表示为1000 0001 注意这里的1000 0001不是2^7+1的二进制。
      * 我们知道int型整数最大值是127 而127的二进制为0111 1111 最高位的符号位不参与运算
      * 所以(-1)& 0x7FFFFFFF -> 1000 0001 & 0111 1111 -> 0000 0001 -> 1    
      */
    public int NumberOf1(int n) {
        int count = 0;       
        //若给的数小于0则通过&运算符转换为正数 因为原来符号位的1被换成了0 所以计数变量count要+1    
        if(n<0){
            count+=1;
            n = n & 0x7FFFFFFF;
        } 
        while(n>0){   
           /*
            * 举个例子n=5时 二进制中有2个1(用4位举例):     
            *     5&4 -> 0101 & 0100 -> 0100 -> 4 count==1
            *     4&3 -> 0100 & 0011 -> 0000 count==2
            * 可以自己多举几个例子观察会发现n&n-1每进行一次就会将n的二进制中最靠右那个1转换为0
            * 这样二进制中有多少个1就会进行多少次这样的操作 我们只要用一个计数变量count存储次数即可
            */   
           n = n & n-1; //效果可以当做结论来使用
           count++;                      
        }
        return count;
    }
}

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {       
        int num = 0,locate = 0;
        //异或全部数字得出不同两个数字的异或结果(相同两个数字异或结果为零,任意数字与零异或结果为其本身 ) 
        for(int i=0;i<array.length;i++){
            num ^= array[i];
        }
        //找出二进制中异或结果为1的位置(能被2整除说明最后一位是0,则循环右移直到找到最右位为1),用cnt记下此刻的位置
        //因为异或的结果是相同为0,不同为1。找到了1的位置表示原来不同的两个数在这个位置上一个是0,一个是1
        while(num%2==0){
            locate++;
            num>>=1;
        } 
        //遍历数组,其他重复的数字右移到相同位置后异或结果仍然为0(不管右移多少位都一样,相同数字彼此异或的结果始终为0)
        for(int i=0;i<array.length;i++){
            //异或cnt位后,为偶的数字中有一个不重复的数字,为奇的数字中也有一个不重复的数字,不断异或分别得出两个数字
            //除了一个不重复的数字外可能没有其他符合if条件的数字
            if((array[i]>>locate)%2==0) num1[0] ^= array[i]; 
            if((array[i]>>locate)%2!=0) num2[0] ^= array[i]; //同上
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38071429/article/details/83928795