剑指offer15.二进制中1的个数
题目链接
题目:编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。
思路一:最朴素的想法,每次判断最低位是否为1,然后进行统计,判断完右移一位。
通过代码:
class Solution {
public:int hammingWeight(uint32_t n) {int res = 0;while(n > 0){if(n & 1)res++;n >>= 1;}return res;}
};
思路二:还可以更快。观察这个运算:n & (n−1)
,其预算结果恰为把n的二进制位中的最低位的1变为0之后的结果。
通过代码:
class Solution {
public:int hammingWeight(uint32_t n) {int res = 0;while(n > 0){n &= n - 1;res++;}return res;}
};
剑指offer16.数值的整数次方
题目链接
题目:实现pow(x, n)
,即计算 x 的 n 次幂函数(即,$ x^n $)。
思路:快速幂。不过需要注意负数的处理。由此引出另一个问题,-2^31转换为正数后是超过int的范围的,需要用long long
。
通过代码:
class Solution {
public:double quickPow(double x, long long n) {double res = 1.0;while(n > 0){if(n & 1){res *= x;n--;}x = x * x;n >>= 1;}return res;}double myPow(double x, int n) {if(n < 0)return 1.0 / quickPow(x, -1 * (long long) n);return quickPow(x, n);}
};
剑指offer56-I.数组中数字出现的次数
题目链接
题目:整数数组sockets
记录了一个袜子礼盒的颜色分布情况,其中sockets[i]
表示该袜子的颜色编号。礼盒中除了一款撞色搭配的袜子,每种颜色的袜子均有两只。请设计一个程序,在时间复杂度O(n),空间复杂度O(1)内找到这双撞色搭配袜子的两个颜色编号。
思路:分组异或。如果除了一个数字以外,其他数字都出现了两次,对这个数组进行全员异或就能快速找到这个数字。由此,针对这道题,将那两个不同的数字拆分到两个数组中,并且每个数组中,其他数字都出现了两次就得到了本题解法。
- 先对所有数字进行一次异或,得到两个出现一次的数字的异或值。
- 在异或结果中找到任意为 1 的位。
- 根据这一位对所有的数字进行分组。
- 在每个组内进行异或操作,得到两个数字。
通过代码:
class Solution {
public:vector<int> sockCollocation(vector<int>& sockets) {int ret = 0;for(int n : sockets)ret ^= n;int div = 1;while((ret & div) == 0)div <<= 1;int a = 0, b = 0;for(int n : sockets){if(n & div)a ^= n;elseb ^= n;}return vector<int> {a, b};}
};
剑指offer56-II.数组中数字出现的次数
题目链接
题目:教学过程中,教练示范一次,学员跟做三次。该过程被混乱剪辑后,记录于数组actions
,其中actions[i]
表示做出该动作的人员编号。请返回教练的编号。
思路:欣赏一下即可。考虑数字的二进制形式,对于出现三次的数字,各二进制位 出现的次数都是 3 的倍数。因此,统计所有数字的各二进制位中 1 的出现次数,并对 3 求余,结果则为只出现一次的数字。
通过代码:
class Solution {
public:int trainingPlan(vector<int>& actions) {int ones = 0, twos = 0;for(int action : actions){ones = ones ^ action & ~twos;twos = twos ^ action & ~ones;}return ones;}
};
剑指offer65.不用加减乘除做加法
题目链接
题目:计算机安全专家正在开发一款高度安全的加密通信软件,需要在进行数据传输时对数据进行加密和解密操作。假定dataA
和dataB
分别为随机抽样的两次通信的数据量:
- 正数为发送量
- 负数为接受量
- 0 为数据遗失
请不使用四则运算符的情况下实现一个函数计算两次通信的数据量之和(三种情况均需被统计),以确保在数据传输过程中的高安全性和保密性。
思路:数字逻辑中的半加器。本位和c
相当于异或运算,进位相当于与运算之后再左移一位。
通过代码:
class Solution {
public:int encryptionCalculate(int dataA, int dataB) {while(dataB){int c = (dataA & dataB) << 1;dataA ^= dataB;dataB = c;}return dataA;}
};