1. 常见位操作
获取
即获取某位是0还是1。方法是将1左右i位,得到形如00010000的值。接着,对这个值与num执行"位与"操作,从而将i位之外的所有位清零。最后,检查该结果是否为0.不为0说明i位为1,否则,i位为0。
// 获取num的第i位是否为1,是则返回1,否则返回0
int getBit(int num, int i)
{
return ((num & (1 << i)) != 0) ? 1 : 0;
}
置位
先将1左移i位,得到形如00010000的值。接着,对这个值和num执行"位或"操作,这样只会改变i位的数据。该掩码i位除外的位均为0,故而不会影响num的其余位。
int setBit(int num, int i)
{
return num | (1 << i);
}
清零
该方法与setBit刚好相反。首先将1左移i位取得形如00010000的值,对这个值取反进而得到类似11101111的掩码。接着,对该掩码和num执行"位与"操作。这样只会清零num的i位,其余位则保持不变。
int resetBit(int num, int i) {
int mask = ~(1 << i);
return num & mask;
}
将num最高位至i位(含)清零:
// 将num最高位至i位(含)清零
int resetBitMSBthroughI(int num, int i) {
int mask = (1 << i) - 1;
return num & mask;
}
将i位至0位(含)清零
// 将i位至0位(含)清零
int resetBitIthrough0(int num, int i) {
int mask = ~((1 << (i + 1)) - 1);
return num & mask;
}
更新
这个方法是将置位和清零合而为一。首先,用诸如11101111的掩码将num的第i位清零。接着,将待写入值v左移i位,得到一个i位为v但其余位都为0的数。最后,对之前取得的两个结果执行"位或"操作,v为1则将num的i位更新为1,否则该为仍为0。
2. 常见题目
只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
int singleNumber(int* nums, int numsSize){
int result = 0;
for (int i = 0; i < numsSize; i++) {
result ^= nums[i];
}
return result;
}
利用"自己和自己位运算的结果是0"的性质。
丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
这题和上题"只出现一次的数字"类似,也是运用 异或 操作:数组中有n个数,并且缺失的数在[0...n]中。因此可以先得到[0...n]的异或值,再将结果对数组中的每个数进行一次异或操作。未缺失的数在[0...n]和数组中各出现一次,因此异或后为0.而缺失的数字只在[0...n]中出现了一次,在数组中没有出现,因此最终的异或值即为这个缺失的数字。在下面的代码,由于[0...n]恰好是这个数组的下标加上n,因此可以用一次循环完成所有的异或值。
#if 0
// 方法一
int missingNumber(int* nums, int numsSize){
int sum = 0;
for (int i = 0; i <= numsSize; i++) {
sum += i;
}
for (int i = 0; i < numsSize; i++) {
sum -= nums[i];
}
return sum;
}
#endif
// 用异或操作
int missingNumber(int* nums, int numsSize){
int result = numsSize;
for (int i = 0; i < numsSize; i++) {
result ^= (i ^ nums[i]);
}
return result;
}
当然,由于这个n的大小有限制,所以也可以用方法一:首先求出[0..n]的和,然后减去数组中所有数的和,就得到了缺失的数字。这个方法也很容易想到。但是如果n很大,就有溢出的风险。所以还是用异或法可靠。
二进制中1的个数
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
int hammingWeight(uint32_t n) {
int count = 0;
while (n > 0) {
count += (n & 1);
n = (n >> 1);
}
return count;
}
比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
这个题目可以 利用上一题"二进制中1的个数"来分别求得每个数的计数。
int hammingWeight(int n) {
int count = 0;
while (n > 0) {
count += (n & 1);
n = (n >> 1);
}
return count;
}
int* countBits(int num, int* returnSize){
(*returnSize) = 0;
if (num < 0) {
return NULL;
}
int *result = (int *)malloc((num + 1) * sizeof(int));
for (int i = 0; i <= num; i++) {
result[i] = hammingWeight(i);
}
(*returnSize) = num + 1;
return result;
}