版权声明:本文自由转载,转载请注明出处。 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]; //同上
}
}
}