x |(x+1)去掉从右开始的第一个0
a^a=0,异或遵循交换律,即只要存在偶数个a,这部分结果为0.
a^0=a 与0异或为本身
寻找奇数
不用加减乘除做加法
二进制进行加法运算时与十进制的思路是一致的,第一部分是不进位部分相加,第二部分是拿到进位的大小,然后将两部分相加。
例如:计算15+07时,第一部分为12,第二部分为10,两部分相加为22.
由于二进制只有0、1两种数字,可以不使用加法,而是通过位运算实现逻辑上的相加。
例如:我们实现5+7, 5: 0101 7: 0111
第一部分:不考虑进位时,相加得到 0010,拆开来看,两个0还是0,一个0一个1是1,两个1是0,即相异时为1,因此可以使用按位异或操作符^ 得到0010也就是2
第二部分:考虑进位的部分,相加得到0101,然后<<1得到1010,只有两个都为1时才为1,然后左移进行进位,因此可使用按位与操作符&, 得到1010也就是10
经过上面两步,我们将5+7转换为了2+10,此时我们发现还需要继续进行加法操作,于是我们重复上述两个部分的操作。
2: 0010 10: 1010
第一部分: 1000即8
第二部分: 0100即4
转换为8+4,继续转换
8: 1000 4: 0100
第一部分:1100即12
第二部分:0000即0
当第二部分需要进位的部分为0时,我们的加法过程就结束了,第一部分就是相加后的最终结果。
int Add(int num1, int num2 ) {
while(num2!=0)
{
int tmp=num1^num2;
num2=(num2&num1)<<1;
num1=tmp;
}
return num1;
}
num1^num2求的是第一部分,(num1&num2)<<1求的是第二部分,第二部分为0时结束。这里我用了tmp来接收第一部分的值,防止影响第二部分值的计算,也可以创建两个变量,使得逻辑更加清晰。
int main()
{
int num1 = 0;
int num2 = 0;
while (num2 != 0)
{
int tmp1=num1^ num2;
int tmp2 = (num1 & num2) << 1;
num1 = tmp1;
num2 = tmp2;
}
}
整数转换(力扣)
寻找单身狗
题目名称:
找单身狗
题目内容:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:有一组数组 1 2 3 4 5 1 2 3 4 6,里面的5和6只出现了一次,想办法找到这两个单身狗。
由前面的题目可知,当一个数出现偶数次时,按位异或的结果为0,如果这组数字只有一个出现奇数次的话,我们直接将所有数字按位异或即可找到单身狗。
但此题有两条单身狗,我们可以将它们分为两组,每组一条单身狗,然后其他数据都是出现偶数次的。
那么如何分类呢?分类的条件是找矛盾,或是找到两个数据的不同点。
5的二进制表示为0101 6的二进制表示为0110 将5^6可以得到 0011,这两个1就是二者的区别,因此我们可以通过最低位是否为1来区分5和6,同时也可以将其它成对数据进行分组。
void search_single_dog(int arr[], int size, int single_dog[])
{
//先将所有数按位异或,找到区分点
int i = 0;
int ret = 0;
for (i = 0; i < size; i++)
{
ret ^= arr[i];
}
//得到0011或其它值,但总有一位为1
//ret=3
int pos = 0;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)//1为0001,将ret的每一位与1&,得到1则最后一位是1
{
pos = i;//用pos标记右移几位开始不同
break;
}
}
//pos=0
for (i = 0; i < size; i++)
{
//pos位置为0的放到dog[0],pos位置为1的放到dog[1]中
if (((arr[i] >> pos) & 1 )== 0)//这里必须注意括号 ==前面的那个必须加,==优先级高于&,否则if一直不会执行,&1==0,先计算1==0,得到0,if语句永远不执行
{
single_dog[1] ^= arr[i];
}
else
{
single_dog[0] ^= arr[i];
}
}
}
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
int size = sizeof(arr) / sizeof(arr[0]);
int single_dog[2] = { 0 };
//创建dog数组用来存放两个单身狗(因为只能返回一个数据,除非传址调用)
search_single_dog(arr, size, single_dog);
printf("%d %d", single_dog[0], single_dog[1]);
}
目录