a=0^a=a^0
0=a^a
由上面两个推导出:a=a^b^b
a=a^b
b=a^b
a=a^b
a=n&(n-1)
diff=(n&(n-1))^n
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1时,结果才为1 |
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
int singleNumber(vector<int>& nums) {
// 10 ^10 == 00
// 两个数异或就变成0
int res = 0;
for(auto n : nums){
res = n ^ res;
}
return res;
}
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
//解法一
//状态机
int singleNumber(vector<int>& nums) {
int a = 0, b = 0;
for(int num : nums){
a = a ^ num & (~b);
b = b ^ num & (~a);
}
return a;
}
//解法二
int singleNumber(vector<int>& nums) {
int res = 0;
for (int i = 0; i < 32; ++i) {
int cnt = 0;
for (auto x : nums) {
cnt += (x>>i)&1;
}
res |= (cnt%3)<<i;
}
return res;
}
给定一个整数数组
nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
vector<int> singleNumber(vector<int>& nums) {
int s = 0;
for(auto n : nums){
s = s ^ n; //先对所有数字进行一次异或,得到两个出现一次的数字的异或值
}
s = (s & (s - 1)) ^ s; // 去掉末尾的1后异或s就得到最后一个1的位置
vector<int> res(2,0);
for(auto n : nums){
if(n & s){
res[0] ^= n;
}else{
res[1] ^= n;
}
}
return res;
}
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
int hammingWeight(uint32_t n) {
int count = 0;
while(n > 0){
n = n & (n - 1);
count++;
}
return count;
}
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
vector<int> countBits(int num) {
vector<int> res;
for(int i = 0; i <= num; i++){
res.push_back(count1(i));
}
return res;
}
int count1(int num){
int count = 0;
while(num != 0){
num &= (num - 1);
count++;
}
return count;
}
另外一种动态规划解法
vector<int> countBits(int num) {
vector<int> res(num + 1);
for(int i = 1; i <= num; i++){
res[i] = res[i & (i - 1)] + 1; // 上一个缺1的元素+1即可
}
return res;
}
颠倒给定的 32 位无符号整数的二进制位。
思路:依次颠倒即可
uint32_t reverseBits(uint32_t n) {
uint32_t res = 0;
int pow = 31;
while(n != 0){
// 把最后一位取出来,左移之后累加到结果中
res += (n & 1) << pow;
n >>= 1;
pow--;
}
return res;
}
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
//解法一
int rangeBitwiseAnd(int m, int n) {
while(m < n){
n &= n - 1;
}
return m & n;
}
//解法二
int rangeBitwiseAnd(int m, int n) {
// m 5 1 0 1
// 6 1 1 0
// n 7 1 1 1
// 把可能包含0的全部右移变成
// m 5 1 0 0
// 6 1 0 0
// n 7 1 0 0
// 所以最后结果就是m<<count
int count = 0; //统计移位次数
while(m != n){
m >>= 1;
n >>= 1;
count++;
}
return n <<= count;
}