文章目录
加法运算
问题:不使用+、-、*、/来完成加法运算。
解法:
public int Add(int num1,int num2) {
while (num2 != 0) {
int temp = num1 ^ num2;
int tmp = (num1 & num2) << 1;
num1 = temp;
num2 = tmp;
}
return num1;
}
原理:
num1 ^ num2
:通过异或(^)运算得到的是在忽略进位情况下,得到的结果。
(num1 & num2) << 1
:与运算(&)得到的是将会产生进位的位,通过向左移位一位得到被异或运算忽略的进位。
然后,再次进行异或运算将进位加到未进位的异或结果上,在这个异或过程中又会产生新的进位并重复这个过程。
实际上,你可以将把进位加到未进位的异或运算看做一次新的加法运算。
当在异或过程中不再产生新的进位时,num2
将会变为0并结束循环,得到结果。
num1 = 15 num2 = 3
(1111 + 0011) = 10010
1111 1111
^ 0011 & 0011
---------- ----------
1100 0011 ---左移1位---> 0110
此时,(自右向左看)产生进位的是1位和2位,需要进位到2位和3位去;观察左移一位后1的位置正好是2位和3位。
重复操作
1100 1100
^ 0110 & 0110
---------- ----------
1010 0100 ---左移一位---> 1000
此时,产生进位的是3位,需要进位到4位去;观察左移一位后1的位置正好是4位。
重复操作
1010 1010
^ 1000 & 1000
--------- ----------
0010 1000 ---左移一位---> 10000
此时,产生进位的是4位,需要进位到5位去;观察左移一位后1的位置正好是5位。
重复操作
00010 00010
^ 10000 & 10000
----------- ----------
10010 00000
至此,得到正确结果(10010 = 18)并且num2变为0退出循环。
统计一个整数的二进制串中1的个数
解法:
public int NumberOf1(int n) {
int count = 0;
while (n != 0) {
count++;
n = n & (n - 1);
}
return count;
}
原理:
count
:用于计数1的个数。
n & (n - 1)
:当一个二进制数减去1时,从右向左看将会使得第一个1变为0。此时将该数减一与该数进行与运算(&)后,因为与运算的特性,该数将保证第一个1被减后其后面一位依旧为0。该数减一将会保证该数第一个1之前的位不会被影响。
此时完成从右向左的第一个1去除,同时原本为0的位依旧为0.
n = 51 = 110011
n - 1 = 110010
110011
& 110010
------------
110010 count = 1
此时,第一个1被置为0
n = 110010
n - 1 = 110001
110010
& 110001
------------
110000 count = 2
此时,第二个1被置为0
n = 110000
n - 1 = 101111
110000
& 101111
------------
100000 count = 3
此时,第三个1被置为0
n = 100000
n - 1 = 011111
100000
& 011111
------------
000000 count = 4
此时,第四个1被置为0
n变为0,退出循环,从count处得到结果(110011 <---> 4)。
END