201. 数字范围按位与
题目描述
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
示例 1
输入: [5,7]
输出: 4
示例 2
输入: [0,1]
输出: 0
解题思路
比较m和n的前缀,取相同的部分。因为当(m,m+1,…n-1,n)进行连续“与操作”时,会抵消很大一部分,而只剩下m(或n)的前缀部分,最后只需将n归位。
如 5(101) 和 7(111) 结果为 4(100),[12,15] 中 12(1100) 和 15(1111) 结果为 12(1100)。
参考来源
https://blog.csdn.net/smile_watermelon/article/details/47320381
LeetCode提交代码
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int i;
for(i=0;m!=n;i++){
m >>= 1;
n >>= 1;
}
return m<<i;
}
};
1720. 解码异或后的数组
题目描述
未知整数数组 arr 由 n 个非负整数组成。
经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 经编码后得到 encoded = [1,2,3] 。
给你编码后的数组 encoded 和原数组 arr 的第一个元素 first(arr[0])。
请解码返回原数组 arr 。可以证明答案存在并且是唯一的。
示例 1
输入:encoded = [1,2,3], first = 1
输出:[1,0,2,1]
解释:若 arr = [1,0,2,1] ,那么 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]
示例 2
输入:encoded = [6,2,7,3], first = 4
输出:[4,2,0,7,4]
提示
2 <= n <= 104
encoded.length == n - 1
0 <= encoded[i] <= 105
0 <= first <= 105
解题思路
a ^ b = c,则有a ^ c = b 或 b ^ c = a,
LeetCode提交代码
class Solution {
public:
vector<int> decode(vector<int>& encoded, int first) {
int len = encoded.size();
vector<int> a(len+1); //创建一个新的“数组”
a[0]={first};
for(int i=0;i<len;i++){
a[i+1] = a[i]^encoded[i]; // 此时可直接赋值
}
return a;
}
};
231. 2的幂
题目描述
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1
输入: 1
输出: true
解释: 20 = 1
示例 2
输入: 16
输出: true
解释: 24 = 16
示例 3
输入: 218
输出: false
易错点
未考虑n<=0的情况。
LeetCode提交代码
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n<=0) return false; // n<=0(易漏)
else return (n&(n-1))==0; // n>0
}
};
137. 只出现一次的数字 II
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1
输入: [2,2,3,2]
输出: 3
示例 2
输入: [0,1,0,1,0,1,99]
输出: 99
解题思路
0 ^ x = x,
x ^ x = 0;
x & ~x = 0,
x & ~0 =x;
LeetCode提交代码
// a为seen_once,b为seen_twice.
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a=0,b=0;
for(int i=0;i<nums.size();i++){
a = (a^nums[i]) & ~b;
b = (b^nums[i]) & ~a;
}
return a;
}
};
260. 只出现一次的数字 III
题目描述
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
示例
输入: [1,2,1,3,2,5]
输出: [3,5]
注意
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
解题思路
题目要求时间复杂度O(N),空间复杂度O(1),可用两个位掩码实现。
bitmask 会保留只出现一次的两个数字(x 和 y)之间的差异。
x & (-x) 是保留位中最右边 1 ,且将其余的 1 设位 0 的方法。
通过 bitmask & (-bitmask) 保留 bitmask 最右边的 1,这个 1 要么来自 x,要么来自 y。
求得x后,通过 bitmask^x 进而求得y。
注:哈希表时间复杂度O(N),空间复杂度O(N),不符合题目要求。
易错点
测试用例为[1,1,0,-2147483648]时,“~bitmask+1”为-bitmask,为2147483648,超过了int的取值范围“-2147483648 ~ 2147483647”,报错。
故本题需要将bitmask为-2147483648的情况单独处理。
LeetCode提交代码
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int bitmask=0; // bitmask为两个出现1次的数中不同的位的二进制数
for(int i=0;i<nums.size();i++){
bitmask ^= nums[i];
}
int bit;
if(bitmask==-2147483648) bit = bitmask;
else bit = bitmask & (~bitmask+1); // bit为bitmask最右边1保留后的二进制数,用于分离两个数
int x=0;
for(int i=0;i<nums.size();i++){
if(nums[i]&bit) // 最右边的1属于nums[i]
x ^= nums[i]; // 通过^消除其他可能符合的重复数字,最终得到其中一个答案
}
return vector<int>{x,x^bitmask};
}
};