剑指Offer刷题日记-位运算
记录剑指Offer中位运算
相关的题目思路及解答。
文章会给出思路和代码,同时为了方便本地调试,还会提供相应的测试用例。
剑指Offer15:二进制中1的个数
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
show me code
1 | int hammingWeight(uint32_t n) |
show me code
1 | int main(int argc, char **agrv) |
剑指Offer56(一):数组中数字出现的次数
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
思路:异或运算
首先,拿hashmap统计次数的方法不行,不满足空间复杂度的要求
异或运算的性质:
- 任何数 x 与 0 异或,结果为 x(恒等律)
- 任何数与自身异或,结果为 0(归零律)
- 异或运算还满足交换律与结合律
以输入的测试vector为例子
1 | 1 ^ 2 ^ 10 ^ 4 ^ 1 ^ 4 ^ 3 ^ 3 = 2 ^ 10 = 0010 ^ 1010 = 1000 |
计算结果是两个只出现一次的数的二进制形式
为什么会出现1000这个结果?
原因是,当数组进行异或运算之后,最后的结果只和两个只出现一次的数有关,其他的数字都被归零了
如果这个数组里面的数字都出现了两次的,那么最后输出的结果一定是0
在测试案例中,因为存在2和10,导致在输出结果的1右到左第四位没有归零(1000)
下面是关键
我们把数组分成两个数组,分组依据是这个数的二进制形式在右到左第四位是0还是1
出现两次的数字右到左第四位一定相同,这样分别在这两个数组中进行异或运算,就能得到出现一次的数字
show me code
1 | vector<int> singleNumbers(vector<int> &nums) |
show me code
1 | int main() |
剑指Offer56(一):数组中数字出现的次数 II
题目:在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字
思路1:hashmap
show me code
1 | int singleNumber(vector<int> &nums) |
思路2:位运算
把数组中每个数字的二进制形式的每一位都加起来,这样出现三次的数字每一位能够被3整除
当某一位不能整除,说明这个出现一次的数字在这里是1
show me code
1 | int singleNumber(vector<int> &nums) |
测试用例
1 | int main() |
剑指Offer65:不用加减乘除做加法
题目:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、×、÷四则运算符号。
思路:位运算
十进制的加法步骤(5+17):
- 不进位加法 12
- 计算进位,且进位的值是10
- 上面两步相加 22
用二进制运算步骤(101+10001)
- 不进位加法 10100
- 计算进位,且进位的值为10(二进制)
- 上面两步相加 10110(22)
转换到位运算上
- 不进位加法 == 异或运算
- 进位 == (a & b) << 1
- 两步相加 ==递归实现,直到没有进位
show me code
1 | int add(int a, int b) |
测试用例
1 | int main() |