Number of 1 Bits
Write a function that takes an unsigned integer and returns the number of ’1’ bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11’ has binary representation 00000000000000000000000000001011, so the function should return 3.
class Solution {
public:
int hammingWeight(uint32_t n) {
int cnt = 0;
while(n){
cnt++;
n &= (n-1);
} return cnt;
}
};
Reverse Bits
Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
unsigned int res = 0;
for(int i = 0; i < 32; i++){
res <<= 1;
res |= (n&1);
n >>= 1;
} return res;
}
};
Counting Bits
Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array.
Example:
For num = 5 you should return [0,1,1,2,1,2].
Follow up:
It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.
思路:这里需要分别求出[0,num]的1’的个数,明显可以考虑用递推关系。
主要有两种递推思路:
方法1:
把数res右移一位,得到的数(int)(res/2)的1’数目已知。 在加上移位丢掉的末尾的bit就是res的1’个数。
递推式:res[i] = res[i >> 1] + (i & 1)
class Solution {
public:
vector<int> countBits(int num) {
vector<int> res(num+1);
for(int i = 1; i <= num; i++){
res[i] = res[i>>1] + (i&1);
} return res;
}
};
方法二: res去掉末尾的最后一个1’后得到的数res’的1’数目已知,再加上去掉的一个1的个数。
递推式:res[i] = res[i&(i-1)] + 1
class Solution {
public:
vector<int> countBits(int num) {
vector<int> res(num+1);
for(int i = 1; i <= num; i++){
res[i] = res[i&(i-1)] + 1;
} return res;
}
};
Single Number
Given an array of integers, every element appears twice except for one. Find that single one.
Note:Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
解析:异或大法:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int single = 0;
for(int i = 0; i < nums.size(); i++){
single ^= nums[i];
} return single;
}
};
Single Number II
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
思路:
还是用位运算的思路,数字在计算机中以2进制存储,我们要做的就是判断出哪一位的bit只出现了1次(与3取模之后为1),所以可以用3进制的方法。
方法一,模拟三进制:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int one = 0, two = 0, three;
for(int i = 0; i < nums.size(); i++){
// two的某bit为1时,右式对应位的计算结果不可能为1,所以不会进位
two |= one & nums[i];
one ^= nums[i];
three = two & one;
two &= ~three;
one &= ~three;
} return one;
}
};
解释一下代码,one代表出现1次的掩码,two代表出现2次的掩码,three代表出现3次的掩码。先考虑某一位bit的情况,用000代表one,two,three的对应bit的值。如果每次该bit都会增加记数:000->100->010->000(先变为110->111->001)。这就可以理解代码的计算过程了,再推广到多bit情况肯定也是正确的。
方法二,k进制:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
const int K = 3;
for(int i = 0; i < 32; i++){
int cnt = 0;
int mask = (1<<i);
for(int j = 0; j < nums.size(); j++){
if(nums[j] & mask){
cnt++;
}
} if(cnt % K){
res |= mask;
}
} return res;
}
};
时间复杂度O(n),空间复杂度O(1)。
Single Number III
Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example: Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].
Note:
The order of the result is not important. So in the above example, [5, 3] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
思路:
根据A Xor B 结果的最后一个1’来把原来的数据划分为两个部分,一部分对应位是1’,另一部分对应位是0’。
代码:
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int A_Xor_B = 0, A = 0, B = 0;
for(int i = 0; i < nums.size(); i++){
A_Xor_B ^= nums[i];
} // A_Xor_B - (A_Xor_B & (A_Xor_B - 1))
int last_bit_pos = A_Xor_B & ~(A_Xor_B-1);
for(int i = 0; i < nums.size(); i++){
if(nums[i] & last_bit_pos){
A ^= nums[i];
} else {
B ^= nums[i];
}
} return vector<int>({A,B});
}
};
Power of Two
思路:二进制表达式表达式只有一个1即可
代码:
class Solution {
public:
bool isPowerOfTwo(int n) {
return n > 0 && (!(n&(n-1)));
}
};
Power of Four
Given an integer (signed 32 bits), write a function to check whether it is a power of 4.
Example:
Given num = 16, return true. Given num = 5, return false.
Follow up: Could you solve it without loops/recursion?
思路:首先要满足二进制表达式表达式只有一个1,还要满足4的次方数的特点。
| 数字|二进制表达式|
| --------- ? --------------- ?
|1 | 0000001|
|4 | 0000100|
|16 | 0010000|
|32|1000000|
|…|…|
然后我们就根据这个规律枚举一下不符合的吧,偶数位上有1的就不是4的次方数。
b:…10101010101010 => 0xAAAAAAAA
代码:
class Solution {
public:
bool isPowerOfFour(int n) {
return n > 0 && !(n&(n-1)) && !(n&0xAAAAAAAA);
}
};
无缓存交换
《程序员面试金典》上的题。
void swap(int& x, int& y){
x = x^y;
y = x^y;
x = x^y;
}
位运算实现加法
《程序员面试金典》上的题。
int add(int x, int y){
int carry = 0;
while(y != 0){
carry = (x&y)<<1;
x ^= y;
y = carry;
} return x;
}
位运算实现max
《程序员面试金典》上的题。
思路,定义一个bool变量use_a
, 我们返回的max就是use_a*a +(1^use_a)*b
. 如果不考虑溢出的问题,只要a-b
大于0时use_a就等于1。如果要考虑溢出的问题,也就是a与b异号的情况,我们需要重新表示use_a
:use_a = (a >= 0 && b < 0) || (a-b)>=0
int sign(int x){
// positive: 1 negative: 0
return 1^((unsigned) x>>31);
}
int getMax(int a, int b) {
int sign_a = sign(a), sign_b = sign(b);
int overflow = sign_a^sign_b;
int use_a = overflow*sign_a + (1^overflow)*sign(a-b);
return use_a*a + (1^use_a)*b;
}