位运算相关算法总结

位运算实现加法

思路:

  1. 异或(^),进行两个数字无进位的相加。
  2. 与(&)后左移一位,得到两个数字相加需进位的位置。
  3. 二者相加,循环这个过程,直到没有需要进位的情况发生。

例子:

6(110)+ 2(010)

  1. 二者异或,得到(100)
  2. 二者相与,得到(010)
  3. 与后左移一位,得到(100)
  4. (100)不为0,需要再次计算(100)与(100)的和
  5. 二者异或,得到(000)
  6. 二者相与,得到(100)
  7. 与后左移一位,得到(1000)
  8. (1000)不为0,需要再次计算(000)与(1000)的和
  9. 二者异或,得到(1000)
  10. 二者相与,得到(0000)
  11. (0000)左移一位,得到(0000)
  12. (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的个数

  1. (101) & (100) = (100)
  2. (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)

  1. (100) & (011) = 0, 所以它是2的幂
  2. (100) & (0101) = 1,所以它是4的幂

8 (1000)

  1. (1000) & (0111) = 0,所以它是2的幂
  2. (1000) & (0101) = 0,所以它不是4的幂

代码:

bool isFour(int n)
{
	if (n & (n-1) == 0 && n & (0x55555555))
		return true;
	else
		return false;
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值