位运算(10题)
2026/4/24 15:17:28 网站建设 项目流程

目录

一、基础知识

1.基础位运算

2.给一个数n,确定它的二进制表示中的第x位是0还是1

3.将一个数n的二进制表示的第x位修改成1

4.将一个数n的二进制表示的第n位修改成0

5.位图的思想

6.提取一个数n,二进制表示中最右侧的1

7.将一个数n二进制表示中最右侧的1抹去

8.位运算的优先级

9.异或 ^,运算的运算律

二、基础题目示例

1.位1的个数

2.比特位计数

3.汉明距离

4.只出现一次的数字

5.只出现一次的数字3

三、题目演示

1.判断字符是否唯一

2.丢失的数字

3.两整数之和

4.只出现一次的数字2

5.消失的两个数字


一、基础知识

1.基础位运算

<< 左移操作符 &按位与 有0就是0

>>右移操作符 | 按位或 有1就是1

~按位取反 ^异或 相同为1,相异为0 / 无进位相加

例如 1 0 1 1 0 1 ^

1 1 0 1 1 0

结果为 0 1 1 0 1 1,无进位相加就是1 + 0 = 0,1+1 = 0,但是不会向高位进位

2.给一个数n,确定它的二进制表示中的第x位是0还是1

我们规定从右往左,的位数为第0,1,2,3,4,5.....31位

这样右移动的距离等于它的位数

(n >> x) & 1 -> 0 ------ 0

1 ------ 1

3.将一个数n的二进制表示的第x位修改成1

n = n | (1 << x)

4.将一个数n的二进制表示的第n位修改成0

n = n &(~(1 << x))

5.位图的思想

每个比特位0或者1的数值表示一种状态

6.提取一个数n,二进制表示中最右侧的1

lowbit = n & -n(取反加一即变为负)

7.将一个数n二进制表示中最右侧的1抹去

n = n & (n - 1)

8.位运算的优先级

能加括号就加括号

9.异或 ^,运算的运算律

1.a ^ a = 0

2.a ^ 0 = a

3.a ^ b ^ c = a ^ (b ^ c)

二、基础题目示例

1.位1的个数

. - 力扣(LeetCode)

class Solution { public: int hammingWeight(int i) { int ret = 0; int n = 32; while(n > 0) { if((i & 1) == 1)ret++; i = i >> 1; n--; } return ret; } };

将要判断的数每次按位与1,若为1则此位为1,然后再右移一位

2.比特位计数

. - 力扣(LeetCode)

class Solution { public: int Add(int i) { int ret = 0; int n = 32; while(n > 0) { if((i & 1) == 1)ret++; i = i >> 1; n--; } return ret; } vector<int> countBits(int n) { vector<int>ret(n+1,0); for(int i = 0; i <= n;i++) { ret[i] = Add(i); } return ret; } };

原理同上,只是多了一个循环

3.汉明距离

. - 力扣(LeetCode)

class Solution { public: int hammingDistance(int x, int y) { int n = 32; int ret = 0; while(n>0) { if((x & 1) != (y & 1))ret++; x = x >> 1; y = y >> 1; n--; } return ret; } };

分别用 &1 来判断两个数最低位是0还是1,对两个数进行比较,然后分别不断右移这两个数

4.只出现一次的数字

. - 力扣(LeetCode)

利用异或的性质即可

class Solution { public: int singleNumber(vector<int>& nums) { int val = 0; for(auto ch:nums) { val ^= ch; } return val; } };

5.只出现一次的数字3

. - 力扣(LeetCode)

class Solution { public: vector<int> singleNumber(vector<int>& nums) { long long n = 0; for(auto ch: nums) { n ^= ch; } long long mask = n &(-n); mask = (int)mask; vector<int>ret(2,0); for(auto ch: nums) { if((ch & mask) == mask)ret[0] ^= ch; else ret[1] ^= ch; } return ret; } };

我们先将所有值异或,这个过程会将相同的数都消去,最后得到两个不同的数a,b异或的结果。

这个数为1的位置,是两个数上值不同的位置。为了方便,我们取出最右侧的1。

a,b两个数中,一个数的该位置为1,一个数为0.

而待分开的数的该位置也一定为1或0.因此我们将全部数分为两组

a,xx yy zz b,mm,nn,oo

这样即可分别取出单独的数

三、题目演示

1.判断字符是否唯一

. - 力扣(LeetCode)

class Solution { public: bool isUnique(string astr) { int size = astr.size(); if(size>26)return false; int bitmap = 0; for(int i = 0; i < size; i++) { int distance = astr[i]-'a'; if(((bitmap >> distance) & 1) == 1)return false; else { bitmap = bitmap | (1 << distance); } } return true; } };

这里我们不使用数据结构,我们使用位图来储存信息,达到减小空间复杂度的效果。每个比特位储存一个字符的存在情况,‘a’的位置是右侧第一位,我们记为0下标。

首先我们记录字符串的长度,来进行遍历操作,如果字符串比26长,那么必定有重复

每次进入循环的时候,我们查看这个字符对应位置是否为1,如果是,我们返回fasle,如果不是,我们将位图的此位改为1.

2.丢失的数字

. - 力扣(LeetCode)

class Solution { public: int missingNumber(vector<int>& nums) { int size = nums.size(); int ret = 0; for(int i = 0; i < size; i++) { ret = ret ^(nums[i]); } for(int i = 0; i <= size; i++) { ret = ret ^ i; } return ret; } };

利用异或的性质,例如

我们选取0-5中的5个数字

1 5 2 3 0

0 1 2 3 4 5

我们用0分别遍历异或上下两组数字,上下两组中相同的数字进过异或都变为0,最后只剩下0-5中剩余的那个数字,也即丢失的数字, 0 ^ 这个数字,仍然为这个数字

3.两整数之和

. - 力扣(LeetCode)

class Solution { public: int getSum(int a, int b) { while(a & b) { int tmp = a; a = a ^ b; b = (tmp & b) << 1; } return a ^ b; } };

我们首先要知道,异或运算是一种无进位相加,那我们如何做到有进位呢?只需要把a按位与b即可,这样我们可以知道哪些位置是要进位的,然后再左移一位,相当于进位操作。

但是进位之后相加还可能再次进位,因此我们循环这个过程,我们不断用a^b,a&b更新a和b的值,直到a&b为0。此时无进位。因为任意数异或0等于它本身,因此我们循环结束统一返回a^b即可

4.只出现一次的数字2

. - 力扣(LeetCode)

class Solution { public: int singleNumber(vector<int>& nums) { int size = nums.size(); int ret = 0; for(int i = 0; i < 32; i++) { int sum = 0; for(auto ch:nums) { sum += (ch >> i)&1; } sum = sum % 3; if(sum)ret = ret | (sum << i); } return ret; } };

原理如上,可以推广,任意重复n次就对n取余

5.消失的两个数字

. - 力扣(LeetCode)

class Solution { public: vector<int> missingTwo(vector<int>& nums) { int size = nums.size()+2; int n = 0; for(int i = 1; i <= size; i++) { n ^= i; } for(auto ch:nums) { n ^= ch; } long long mask = n &(-n); vector<int>ret(2); for(int i = 1; i <= size; i++) { if((i & mask) == mask)ret[0] ^= i; else ret[1] ^= i; } for(auto ch:nums) { if((ch & mask) == mask)ret[0] ^= ch; else ret[1] ^= ch; } return ret; } };

与基础题目示例中的5.只出现一次的数字3相似,只是遍历范围是一个数组加上一串连续的数字

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询