前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是七月集训第十天:位运算🔥
一、练习题目
面试题 16.01. 交换数字
1342. 将数字变成 0 的操作次数
476. 数字的补数
2044. 统计按位或能得到最大值的子集数目
二、算法思路
- 1、面试题 16.01. 交换数字:🔥利用异或的性质。
- 2、1342. 将数字变成 0 的操作次数:🔥递归即可。
- 3、476. 数字的补数:🔥 我们首先要做的就是找到num的最高位然后左移一位减一得到num现有位都为1的数字,比如5 : 101 ,最高位为:100 ,左移一位减一得到 111。
- 4、2044. 统计按位或能得到最大值的子集数目:🔥🔥记 n 是数组 nums 的长度,数组中的每个元素都可以选取或者不选取,因此数组的非空子集数目一共有 (2^n-1) 个。可以用一个长度为 n 比特的整数来表示不同的子集,在整数的二进制表示中,n 个比特的值代表了对数组不同元素的取舍。第 i 位值为1则表示该子集选取对应元素,第 i 位值为0则表示该子集不选取对应元素。求出每个子集的按位或的值,并计算取到最大值时的子集个数。
三、源码剖析
// 面试题 16.01. 交换数字
class Solution {
public:
vector<int> swapNumbers(vector<int>& numbers) {
numbers[0] = numbers[0] ^ numbers[1]; //(1)
numbers[1] = numbers[0] ^ numbers[1]; //(2)
numbers[0] = numbers[0] ^ numbers[1]; //(3)
return numbers;
}
};
- 1、这里指的是 a = a ^ b;
- 2、这里指的是b = a ^ b ^ b = a,也就是说numbes[1] = numbers[0]了;
- 3、这里指的是a = a ^ b ^ a = b。
// 1342. 将数字变成 0 的操作次数
class Solution {
public:
int numberOfSteps(int num) {
if(num == 0) {
return 0;
}
if(num & 1) {
return numberOfSteps(num - 1) + 1;
} else {
return numberOfSteps(num / 2) + 1;
}
}
};
- 1、递归按照题目意思做。
// 476. 数字的补数
class Solution {
public:
int findComplement(int num) {
unsigned int k = 1;
while(k < num) {
k <<= 1; //(1)
}
if(k == num) { //(2)
return k - 1;
}
return k - 1 - num; //(3)
}
};
- 1、找到一个k >= num,k是一个2次,例如5:101,大于等于它的k是1000;
- 2、k如果等于num说明num也是一个2次幂函数,所以取反就是把k - 1;
- 3、如果k大于num,就像1的例子5,我们只要把k-1-num即可求出。
// 2044. 统计按位或能得到最大值的子集数目
class Solution {
public:
int countMaxOrSubsets(vector<int>& nums) {
int n = nums.size();
int state = 1 << n, max = 0, ans = 0;
for (int i = 0; i < state; i++){
int cur = 0;
for (int j = 0; j < n; j++){
if ((1 << j) & i){
cur |= nums[j];
}
}
if (cur > max){
max = cur;
ans = 1;
} else if (cur == max){
ans++;
}
}
return ans;
}
};
- 1、位运算。