力扣位运算

x ^ 0s = x
x ^ x = 0
n & (n - 1) 可以去除 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,减去 1 得到 11110011,这两个数按位与得到 11110000。n & (-n) 可以得到 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,取负得到 00001100,这两个数按位与得到 00000100。
给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。
对两个数进行按位异或操作,统计有多少个 1 即可。

int hammingDistance(int x, int y) {
    
    
int diff = x ^ y, ans = 0;
while (diff) {
    
    
ans += diff & 1;
diff >>= 1;
}
return ans;
}

给定一个十进制整数,输出它在二进制下的翻转结果。

uint32_t reverseBits(uint32_t n) {
    
    
uint32_t ans = 0;
for (int i = 0; i < 32; ++i) {
    
    
ans <<= 1;
ans += n & 1;
n >>= 1;
}
return ans;
}

给定一个整数数组,这个数组里只有一个数次出现了一次,其余数字出现了两次,求这个只出现一次的数字。
我们可以利用 x ∧ x = 0 和 x ∧ 0 = x 的特点,将数组内所有的数字进行按位异或。出现两次的所有数字按位异或的结果是 0,0 与出现一次的数字异或可以得到这个数字本身。

int singleNumber(vector<int>& nums) {
    
    
int ans = 0;
for (const int & num: nums) {
    
    
ans ^= num;
}
return ans;
}

给定一个整数,判断它是否是 4 的次方。
首先我们考虑一个数字是不是 2 的(整数)次方:如果一个数字 n 是 2 的整数次方,那么它的二进制一定是 0…010…0 这样的形式;考虑到 n − 1 的二进制是 0…001…1,这两个数求按位与的结果一定是 0。因此如果 n & (n - 1) 为 0,那么这个数是 2 的次方。如果这个数也是 4 的次方,那二进制表示中 1 的位置必须为奇数位。我们可以把 n 和二进制的 10101…101(即十进制下的 1431655765)做按位与,如果结果不为 0,那么说明这个数是 4 次方。
4的幂一定是2的。
4的幂和2的幂一样,只会出现一位1。但是,4的1总是出现在奇数位。
0x5 = 0101b可以用来校验奇数位上的1。
那么,

//0x5 = 0101b
bool isPowerOfFour(int num) {
    
    
    if (num < 0 || num & (num-1)){
    
    //check(is or not) a power of 2.
        return false;
    }
    //是2的N次幂(有一个1)且出现在奇数位上
    return num & 0x55555555;//check 1 on odd bits
}

给定多个字母串,求其中任意两个字母串的长度乘积的最大值,且这两个字母串不能含有相同字母。

Input: ["a","ab","abc","d","cd","bcd","abcd"]
Output: 4

在这个样例中,一种最优的选择是“ab”和“cd”。
怎样快速判断两个字母串是否含有重复数字呢?可以为每个字母串建立一个长度为 26 的二进制数字,每个位置表示是否存在该字母。如果两个字母串含有重复数字,那它们的二进制表示的按位与不为 0。同时,我们可以建立一个哈希表来存储字母串(在数组的位置)到二进制数字的映射关系,方便查找调用。

int maxProduct(vector<string>& words) {
    
    
unordered_map<int, int> hash;
int ans = 0;
for (const string & word : words) {
    
    
int mask = 0, size = word.size();
for (const char & c : word) {
    
    
//用|是出现过就行
mask |= 1 << (c - ’a’);
}
//字母种类相同 对应存的是最大长度
hash[mask] = max(hash[mask], size);
for (const auto& [h_mask, h_len]: hash) {
    
    
if (!(mask & h_mask)) {
    
    
//当前与已存的挨个按位与 当为0则无重复符号
ans = max(ans, size * h_len);//取最大乘积
}
}
}
return ans;
}

给定一个非负整数 n,求从 0 到 n 的所有数字的二进制表达中,分别有多少个 1。

Input: 5
Output: [0,1,1,2,1,2]

本题可以利用动态规划和位运算进行快速的求解。定义一个数组 dp,其中 dp[i] 表示数字 i的二进制含有 1 的个数。对于第 i 个数字,如果它二进制的最后一位为 1,那么它含有 1 的个数则为 dp[i-1] + 1;如果它二进制的最后一位为 0,那么它含有 1 的个数和其算术右移结果相同,即dp[i>>1]。

vector<int> countBits(int num) {
    
    
vector<int> dp(num+1, 0);
for (int i = 1; i <= num; ++i)
dp[i] = i & 1? dp[i-1] + 1: dp[i>>1];
// 等价于dp[i] = dp[i&(i-1)] + 1;
return dp;
}

Guess you like

Origin blog.csdn.net/qq_45598881/article/details/121389130