-->

[LeetCode]Reverse Bits

2020-02-27 12:58发布

题目:Reverse Integer

Reverse digits of an integer.

Example1: x = 123, return 321
Example2: x = -123, return -321

Have you thought about this?

Here are some good questions to ask before coding. Bonus points for you if you have already thought through this!

If the integer's last digit is 0, what should the output be? ie, cases such as 10, 100.

Did you notice that the reversed integer might overflow? Assume the input is a 32-bit integer, then the reverse of 1000000003 overflows. How should you handle such cases?

For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

Note:
The input is assumed to be a 32-bit signed integer. Your function should return 0 when the reversed integer overflows.

反转数字;

注意:

  1. 末尾是0时反转后无效,例如:100->1
  2. 负数翻转后还是负数;
  3. 翻转后溢出则返回0

考虑上面的几种情况,可以有下面的实现

int reverse(int x) {
    bool flag = x >= 0;//保存符号
    long long result = 0L;//使用long long 防止溢出
    long long xL = abs((long long)x);//求绝对值
    while (xL){
        result = result * 10 + xL % 10;
        if (result > INT_MAX)return 0;//溢出
        xL /= 10;
    }
    if(flag)return (int)result;//还原符号
    return -(int)result;
}

但是上面的方法不够简单:

int reverse(int x) {
    int result = 0;
    while (x) {
        int temp = result * 10 + x % 10;//暂存,看是否溢出
        if (temp / 10 != result)return 0;//无法还原,表示溢出
        result = temp;
        x /= 10;
    }
    return result;
}

题目: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).

Follow up:
If this function is called many times, how would you optimize it?

给定32位无符号整数,返回它的二进制反向的值。

思路:

用移位的方式,这样每次只需要移位64次就能求出最后的值。

具体来说结果值k向左移位一次,然后将n的最后一位给k的最后一位,再将n右移一位。

uint32_t reverseBits(uint32_t n) {
    unsigned int k = 0;
    for (size_t i = 0; i < 32; i++){
        k = k << 1;
        k = k | (n & 0x01);//n的最低位传递给k
        n = n >> 1;
    }
    return k;
}  

思路2:

下面的思路可用于固定长度的二进制位的逆置,每次逆置一半。

//abcdefgh -> efghabcd -> ghefcdab -> hgfedcba
uint32_t reverseBits(uint32_t n) {
    n = (n >> 16) | (n << 16);//前一半和后一半换位
    n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);//前一半和后一半都均匀分成两半,在互换位置
    n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
    n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
    n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
    return n;
}

 题目: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.

统计一个整数的二进制表示中1的个数。

思路:

每次判断最低位是1则计数加一,然后右移一位,循环32次就能知道1的个数。

int hammingWeight(uint32_t n) {
    int k = 0;
    for (size_t i = 0; i < 32; i++){
        if (n & 0x01 == 0x01)++k;//是1则加一
        n = n >> 1;//右移一位
    }
    return k;
}

思路2:

还可以通过n & (n - 1)来统计最低位置的一个1。n - 1会使得最低位的1变为0,其后面的0都变为1,这样n & (n - 1)最低位的1变为0。

例如:n = 44 = (00101100)

第一次 n = 00101100, 那么 n - 1 = 00101011, 所以 n & (n - 1) = 00101100 & 00101011 = 00101000. Count = 1.
第二次 n = 00101000, 那么 n - 1 = 00100111, 所以 n & (n - 1) = 00101000 & 00100111 = 00100000. Count = 2.
第三次 n = 00100000, 那么 n - 1 = 00011111, 所以 n & (n - 1) = 00100000 & 00011111 = 00000000. Count = 3.

int hammingWeight(uint32_t n) {
    int k = 0;
    while (n){
        n &= (n - 1);//去掉第一个1
        ++k;
    }
    return k;
}

题目: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.

给定一个非负整数num。 对于范围为0≤i≤num的每个数字,我们计算其二进制表示中的1的数量并将其值放到数组中返回。

思路:由上面统计1的思想,可以看出i的1的个数和第j = i&(i-1)中1的个数的关系。

即动态规划的思想:设F(i)表示数i中1的个数,F(i) = F(i&(i-1)) + 1;

vector<int> countBits(int num) {
    vector<int>arr(num + 1, 0);
    for (size_t i = 1; i <= num; ++i){
        arr[i] = arr[i & (i - 1)] + 1;
    }
    return arr;
}

题目:Hamming Distance

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.

Given two integers x and y, calculate the Hamming distance.

Note:
0 ≤ xy < 231.

Example:

Input: x = 1, y = 4
Output: 2
Explanation:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑
The above arrows point to positions where the corresponding bits are different.

求汉明距离;两个数字之间的汉明距离就是其二进制数对应位不同的个数。

思路:

将两个数异或,使得不同的位数变为1,相同的为0,接下来统计1的个数即可。

int hammingDistance(int x, int y){
    int z = x ^ y;//异或:不同为1
    int count = 0;
    while (z){
        if (z & 0x01 == 0x01)++count;//统计1的个数
        z >>= 1;
    }
    return count;
}

题目:Total Hamming Distance

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.

Now your job is to find the total Hamming distance between all pairs of the given numbers.

Example:

Input: 4, 14, 2

Output: 6

Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just
showing the four bits relevant in this case). So the answer will be:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.

Note:

  1. Elements of the given array are in the range of to 10^9
  2. Length of the array will not exceed 10^4.

思路:

当数字的相同位置的01不同时,会增加汉明距离,多个数0和1的不同组合次数,就是当前位置增加的汉明距离,因此只要知道该位置中0和1的数目就可以求出其增加的汉明距离。

例如:

Arr[] = {4,14,2,8};

0000 0100

0000 1110

0000 0010

0000 1000

前八个位置的0和1的个数:0:{4,2,2,2,4,4,4,4};1:{0,2,2,2,0,0,0,0}

则按照数组中的统计结果,第二个位置0有2个,1有2个;4个数的不同组合在第二个位置会产生2*2=4的汉明距离。

详细实现:

按照上面的分析,只需要统计所有数字中每个位置的0和1的数目最后乘起来在相加,就能得到结果。

时间复杂度O(32n),空间复杂度O(n)。

int LeetCode::totalHammingDistance(vector<int>& nums){
    vector<int>zero(32, 0), one(32, 0);
    for (auto n : nums){
        int i = 0;
        while (n){
            if (n & 0x01 == 0x01)++one[i];//是1,one对应位置加一
            else ++zero[i];
            n >>= 1;
            ++i;
        }
        while (i < 32)++zero[i++];//后面全是0,剩余的0的位置加一
    }
    int result = 0;
    for (size_t i = 0; i < 32; i++){
        result += zero[i] * one[i];//每一个位置0和1不同的组合数
    }
    return result;
}

题目:Power of Two

Given an integer, write a function to determine if it is a power of two.

判断一个数是否是2的幂。

思路:

不停的除以2最后为1则是2的幂。

bool LeetCode::isPowerOfTwo(int n){
    if (!n)return false;
    while ((n&0x01) != 0x01){//2的次方则只有最高位是1
        n = n >> 1;
    }
    return n == 1;
}

思路2:

2的幂,只有一个1,则可以通过统计1的方法n&(n-1)来判断是否为2的幂;

如果n&(n-1)为0,则是2的幂。

bool LeetCode::isPowerOfTwo(int n){
    //2的幂只有一个1,则使用n&(n-1)来统计1的个数
    return n > 0 && !(n & (n - 1));
}

题目:Power of Three

Given an integer, write a function to determine if it is a power of three.

Follow up:
Could you do it without using any loop / recursion?

判断一个数是否是3的幂。

思路:

不停的除以3最后为1则是3的幂。

bool isPowerOfThree(int n) {
    while (n >= 3){
        if (n % 3)return false;
        n /= 3;
    }
    return n == 1;
}

思路2:但是要求不适用递归和循环。

int的数是有限的找到最大的3的幂使用它对给定的数求余,结果为0表示3的幂。

int中最大的3的幂是:1162261467

bool isPowerOfThree(int n) {
    return n > 0 && !(1162261467 % n);
}

题目: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?

判断一个数是否是4的幂。

思路:

与判断2的幂相比,4中1的位置必定是在奇数的位置。

使用0x55555555使得奇数上的1被保留。

bool isPowerOfFour(int n){
    return n > 0 && !(n & (n - 1)) && ((n & 0x55555555) == n);//0x55555555保证在奇数的位置上的1被保留
}

思路2:

与判断2的幂相比,4的幂满足(n - 1)%3 == 0。

证明详细过程不再赘述,简单来讲,可以考虑(n-1) = (2^k - 1)*(2^k + 1),这样不停的分解下去就能分解出3的因子。

bool isPowerOfFour(int n){
    return n > 0 && !(n & (n - 1)) && !((n - 1)%3);
}

 

标签: