寒假刷题打卡第二十&二十一天 | 位运算

  1. 汉明距离
class Solution {
public:
    int hammingDistance(int x, int y) {
        int res = abs(x) ^ abs(y);
        int count = 0;
        while(res)
        {
            //if(res & 1)
            //    count++;
            res = res & (res - 1);
            count++;
        }
        return count;
    }
};
  1. 只出现一次的数字
  2. 丢失的数字
    这道题出了可以用位运算来做,还可以通过求和来做。但是要注意,求和有溢出的风险,最好就是一边求和,一边做减法。
  3. 只出现一次的数字 III
    两个收获:
    1.最开始把 while((res&1)0) 写成得是 while(res&10),答案死活不对。因为优先级不对。
    2.如何判断某个数的二进制表示中某一位是否为1.参看注释。
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int res = 0;
        for(int x : nums)
            res ^= x;
        int pos = 1;
        //while((res&1)==0)  // == 的优先级高于&
        //{
        //    pos++;
        //    res = res>>1;
        //}
        //cout << "pos: " << pos << endl;
        //int flag = 1;
        //while(--pos)
        //{
        //    flag = flag << 1;
        //}
        // 上面的思路是先找出位置,再去构造这个数,实际上可以直接构造出这个数
        while((res&1)==0)  // == 的优先级高于&
        {
            pos <<= 1;
            res = res>>1;
        }
        int num1 = 0, num2 = 0;
        for(int x : nums)
        {
            if(pos & x) //判断x的第pos个数是否为1
                num1 ^= x;
            else
                num2 ^= x;
        }
        return {num1, num2};
    }
};
  1. 颠倒二进制位
    位运算还是都加括号吧,看了评论区,好多人也都有这个问题。
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t ans = 0;
        int run = 32;
        while(run--)  //注意这个地方不能是n,因为如果是n的话,有可能不能执行32次
        {
            ans = (ans<<1) + (n & 1);
            n >>= 1;
        }
        return ans;
    }
};

进阶解答一脸懵逼,看了这篇文章后终于清楚了。

  1. 不用额外变量交换两个数
a = a ^ b;
b = a ^ b;
a = a ^ b;
  1. 判断是否是2的幂
    最直接的思路当然是把这个数一直除以二,每次都判断它的余数是否为0。复杂度为log(N)
    另一个思路就是2的幂的二进制表示中只有一个数是1.所以,统计1的个数。
class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n==0)  // 第一次提交跪在了这儿
            return false;
        int count = 0;
        while(n)
        {
            count += (n & 1);
            if(count > 1)
                return false;
            n >>= 1;
        }
        return true;
    }
};

上面的实现很复杂,利用性质,能有更简单的实现
n & (-n) : 得到 n 的位级表示中最低的那一位 1。
n & (n - 1) : 去除 n 的位级表示中最低的那一位 1。

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n<=0)
            return false;
        return (n & (n - 1)) == 0; // 加括号! 加括号! 加括号!
    }
};
  1. 4的幂
    这道题和上一道题的区别在于,4的幂中1在奇数位上。判断是否在奇数位上,可以这样写:n & 10101010101 != 0
    但是C++中没有二进制表示,所以,有如下十六进制 表示:
0xaaaaaaaa = 10101010101010101010101010101010    左边有8个a,右边有320\1,偶数位为1,奇数位为00x55555555 = 1010101010101010101010101010101 (偶数位为0,奇数位为10x33333333 = 110011001100110011001100110011 (10每隔两位交替出现)

0xcccccccc = 11001100110011001100110011001100 (01每隔两位交替出现)

0x0f0f0f0f = 00001111000011110000111100001111 (10每隔四位交替出现)

0xf0f0f0f0 = 11110000111100001111000011110000 (01每隔四位交替出现)

所以,代码如下:

class Solution {
public:
    bool isPowerOfFour(int n) {
        if(n<=0 || (n & (-n))!=n)
            return false;
        return n & 0x55555555;  //判断是否在奇数位上
    }
    int posOf1(int n)
    {
        int pos = 1;
        while((n&1)==0)
        {
            pos++;
            n >>= 1;
        }
        return pos;
    }
};
  1. 交替位二进制数
    评论区:将n右移一位后与n异或,结果全为1.
class Solution {
public:
    bool hasAlternatingBits(int n) {
        int num = n^(n>>1);
        return ((num+1) & num) == 0;
    }
};
  1. 求一个数的补码
    任何一个数异或111111(位数和它本身相同)都会变为它的补码。
  2. 不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和
    怎么解决负数的问题,还需要参考一下剑指offer。
class Solution {
public:
    int getSum(int a, int b) {
        int x = a ^ b;
        int y = (unsigned int)(a & b);
        while(y)
        {
            y <<= 1;
            int temp = x;  //这个地方如果不事先保存x的值的话是不对的。
            x = x ^ y;
            y = (unsigned int)(temp & y);
        }
        return x;
    }
};
  1. 最大单词长度乘积
    收获:利用位掩码判断两个字符串是否含有相同的字母。

  2. 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
    我的解答:
    主要是通过找规律

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> ans(num+1, 0);
        int gap = 1;
        int start = 0;
        int pos = 1;
        while(pos < num+1)
        {
            int nextGap = 2 * gap;
            while(gap-- && (pos < num+1))
            {
                ans[pos++] = 1 + ans[start++];
            }
            start = 0;
            gap = nextGap;
        }
        return ans;
    }
};

位运算:
利用 x&(x-1)能消去最右边的1,所以x的1的数量就是x&(x-1)中1的数量加1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值