位运算实现加法
思路:
- 异或(^),进行两个数字无进位的相加。
- 与(&)后左移一位,得到两个数字相加需进位的位置。
- 二者相加,循环这个过程,直到没有需要进位的情况发生。
例子:
6(110)+ 2(010)
- 二者异或,得到(100)
- 二者相与,得到(010)
- 与后左移一位,得到(100)
- (100)不为0,需要再次计算(100)与(100)的和
- 二者异或,得到(000)
- 二者相与,得到(100)
- 与后左移一位,得到(1000)
- (1000)不为0,需要再次计算(000)与(1000)的和
- 二者异或,得到(1000)
- 二者相与,得到(0000)
- (0000)左移一位,得到(0000)
- (0000)为0,故得到最终结果 8(1000)
代码:
int plus(int num1, int num2)
{
if(num2 == 0)
return num1;
return plus(num1 ^ num2, (num1 & num2)<<1);
}
不用* / mod符号实现整型数字的除法
思路:
用减法模拟除法,但是循环减除数的效率太低,为O(n/k)。利用位运算将效率能够提升至O(log(n/k))。位运算左移一位相当于得到这个数字的两倍。通过位运算得到小于被除数的最大除数的倍数,并记录这是原除数的几倍。再让被除数逐渐减去右移的除数,直至被除数不再大于0,在这个过程中不断累加当前除数是原除数几倍的这个值,最后这个值即为结果。注意考虑符号及整型变量的取值范围。
例子:
long count = 0;
long bit = 1;
while(new_dividend >= new_divisor << 1)
{
new_divisor <<= 1;
bit <<= 1;
}
while(bit > 0 && new_dividend > 0)
{
if(new_dividend >= new_divisor)
{
new_dividend = new_dividend - new_divisor;
count += bit;
}
bit >>= 1;
new_divisor >>= 1;
}
交换两个数字的值(不使用临时变量)
思路:
利用两个相同的数异或为0,任何数与0异或为该数本身
例子:
交换a 与 b的值
a = a ^ b
b = a ^ b = ((原本的a) ^ b )^ b
a = a ^ b = a ^ (a ^ (原本的b))
代码:
void exchange(int& num1, int& num2)
{
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
}
找出数组中唯一一个不重复的数字
整型数组中只有一个整数只出现了一次,其他整数都出现了两次,找出出现一次的这个整数,并返回。
思路:
利用两个相同的数异或为0,任何数与0异或为该数本身,把数组中各个数字依次异或,最终得到的结果就是那个唯一不重复的数字。
例子:
[1,2,3,3,2]
1 ^ 2 ^ 3 ^ 3 ^ 2 = 1
代码:
int findNoDup(vector<int> nums)
{
int ans = 0;
for(int i = 0; i < nums.size(); i++)
{
ans = ans ^ nums[i];
}
return ans;
}
一个数字二进制形式中1的个数
思路:
n & (n - 1) 会使n的二进制中最后一位1变成0,利用这一点计数,直到把n所有的1都变为0。
例子:
5(101)二进制中1的个数
- (101) & (100) = (100)
- (100) & (011) = (000)
所以,5(101)一共有两个1
代码:
int numOfOne(int num)
{
int count = 0;
while (num)
{
num = num & (num - 1);
count ++;
}
return count;
}
判断一个数是否为2的幂
思路:
如果一个数字n是2的幂,则n 与 (n - 1) 二进制上每一位都是不同的,相与的结果值为0。
例子:
3 (11) 与 2 (10) 的二进制数不是每一位都不同,故3不是2的幂。
4 (100) 与 3 (011) 的二进制数是每一位都不同,故4是2的幂。
代码:
bool isTwo(int num)
{
if (num & (num - 1))
return false;
else
return true;
}
判断一个数是否为4的幂
思路:
一个数是4的幂一定是2的幂,先判断其是否为2的幂;如果是,则其二进制数中只有一个数是1,其余都是0;再判断这个1是否在应该在的位置,如果是4的幂,则其二进制数字中1所在的位只可能是从最低位开始,从后每隔两位所在的位置,用n与上01010101…01010101这个数即可判断是否是4的幂。
例子:
4 (100)
- (100) & (011) = 0, 所以它是2的幂
- (100) & (0101) = 1,所以它是4的幂
8 (1000)
- (1000) & (0111) = 0,所以它是2的幂
- (1000) & (0101) = 0,所以它不是4的幂
代码:
bool isFour(int n)
{
if (n & (n-1) == 0 && n & (0x55555555))
return true;
else
return false;
}