位运算---总结

发布于:2025-04-21 ⋅ 阅读:(20) ⋅ 点赞:(0)

位运算

基础

1. & 运算符 : 有 0 就是 0
2. | 运算符 : 有 1 就是 1
3. ^ 运算符 : 相同为0 相异为1 and 无进位相加
  1. 位运算的优选级

    不用在意优先级,能加括号就加括号
    
  2. 给一个数 n ,确定它的二进制位中第 x 位是 0 还是 1?

规定: 题中所说的第x位指:int 在32位机器下4个字节32位,从右向左依次增加,从0位开始,即 第 0 位 到第 31 位.
(n >> x) & 1 
  1. 将一个数 n 的二进制位表示的第 x 位修改为 1
n |= (1 << x)
  1. 将一个数 n 的二进制表示的 第 x 位修改为 0
n &= ~(1 << x) 
  1. 提取一个数 n 二进制表示中最右侧的1
n & -n;
-n : 将最右侧的1左边的区域全部变为相反数,右边的1的数不变(本来就是0)
    0 1 1 0 1 0 1 0 0 0 
~   1 0 0 1 0 1 0 1 1 1
+1  1 0 0 1 0 1 1 0 0 0
n:  0 1 1 0 1 0 1 0 0 0 
------------------------
	0 0 0 0 0 0 1 0 0 0
  1. 干掉一个数( n )二进制表示中最右侧的1
n &= (n -1)
  1. 异或(^)运算的运算律
1. a ^ 0 = a;
2. a ^ a = 0; 消消乐
3. a ^ b ^ c = a ^ (b ^ c) 符合交换律和结合律

异或
无进位相加解释:
1 0 1 1 0 1 0
0 0 1 0 1 0 1
1 0 1 0 0 0 0
-------------
0 0 1 1 1 1 1   --> 两个 1 会消消乐(本质就是1的抵消), 即无进位相加 

题目练习

191.位1的个数

思路一:依次判断每个位是否为1,为 1 ans++;
class Solution {
public:
    int hammingWeight(int n) {
        int ans = 0;
        int sum = 32;
        for(int i = 0; i < 32; i++)
        {
            if((n >> i) & 1)
            {
                ans++;
            }
        }
        return ans;
    }
};

思路二:依次消除最低位的 1, 消除一次 ans++;
class Solution {
public:
    int hammingWeight(int n) {
        int ans = 0;
        while(n)
        {
            n &= (n -1);
            ans++;
        }
        return ans;
    }
};

338. 比特位计数

思路:依次消除最低位的 1, 消除一次 count++; 对每个数字统计一次即可
class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> ans;
        for(int i = 0; i <= n; i++)
        {
            int count = 0;
            int temp = i;
            while(temp)
            {
                temp &= (temp - 1);
                count++;
            }
            ans.push_back(count);
        }
        return ans;
    }
};

461. 汉明距离

//思路:先异或(相同为0相异为1)后统计1的个数
class Solution {
public:
    int hammingDistance(int x, int y) {
        x ^= y;
        int ans = 0;
        while(x)
        {
            x &= (x -1);
            ++ans;
        }
        return ans;
    }
};

136. 只出现一次的数字

//思路:利用异或运算规律:
// 1. a ^ a = 0; 
// 2. a ^ 0 = a 
// 3. 交换律和结合律
class Solution {
public:
    int singleNumber(vector<int>& nums) {     
        int ans = 0;
        for(int iter : nums)
        {
            ans ^= iter;
        }
        return ans;
    }
};

260. 只出现一次的数字 III

//思路:利用异或的规律,将所有数据异或一次,结果一定是只出现一次的两个元素异或后的结果,然后利用异或的相同为 0 相异为 1,并用最低位 1 来区分两个只出现一次的元素,划分为两个集合(此时每个集合中只有一个数出现一次,其他数都出现了两次),分别异或即可得到结果
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        unsigned int xor_all = 0; 
        //为什么使用unsigned int ?
        //使用int可能会导致溢出
        //unsigned int 自动会进行模运算,保证结果始终在unsigned int 表示范围内
        //int: (-2^31 到 2^31 - 1)
        //unsigned int: (0 ~ 2^32 -1)
        for(int iter : nums)
        {
            xor_all ^= iter;
        }
        //获取异或结果的最低位为 1 的位 
        int lowbit = xor_all & (-xor_all);
        vector<int> ans(2);
        for(int x : nums)
        {
            if((x & lowbit) == 0)
            {
                ans[1] ^= x;
            }
            else
            {
                ans[0] ^= x;
            }
        }
        return ans;
    }
};

面试题 01.01. 判定字符是否唯一

思路:使用hash表统计每个字符出现的次数,然后遍历hash表即可
class Solution {
public:
    bool isUnique(string astr) {
        unordered_map<char,int> hash;
        for(int i = 0; i < astr.size(); i++)
        {
            hash[astr[i]]++;
        }
        for(auto iter : hash)
        {
            if(iter.second > 1)
            {
                return false;
            }
        }
        return true;
    }
};

class Solution {
public:
    bool isUnique(string astr) {
        //利用位图思想来解决问题
        if(astr.size() > 26)
        {
            return false;
        }
        int bitmap = 0;
        for(char c : astr)
        {
            int n = c - 'a';
            //判断字符是否已经出现过
            if(bitmap & (1 << n))
            {
                return false;
            } 
            else
            {
                bitmap |= (1 << n);
            }
        }
        return true;
    }
};

268. 丢失的数字

//利用异或的规则:将0~n的数字和 nums中的数字都异或一次结果即为没有出现的那个数,其他数都出现了两次
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        unsigned int xor_all = 0;
        int n = nums.size();
        for(int i = 0; i <= n; i++)
        {
            xor_all ^= i;
        }
        for(int x : nums)
        {
            xor_all ^= x;
        }
        return xor_all;
    }
};

371. 两整数之和

//思路:先使用无进位相加,计算进位,无进位相加直到进位为0
class Solution {
public:
    int getSum(int a, int b) {
        while(b != 0)
        {
            int x = a ^ b;//计算无进位相加
            int carry = ( a & b) << 1; ;//计算进位
            a = x;
            b = carry;
        }
        return a;
        
    }
};

137. 只出现一次的数字 II

//思路:统计每个数字第i位的和sum, sum %= 3 即可判断只出现一次的数字第i位
//3n 0 + 0 = 0  %=3 == 0
//3n 0 + 1 = 1  %=3 == 1
//3n 1 + 1 = 3n + 1 %3 == 1
//3n 1 + 0 = 3n  %=3 == 1  -->此方法可推广到n,即除某个元素只出现一次外,其他元素都出现了n次,%=n 即可判断只出现一次的数字的第i位
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for(int i = 0; i < 32; i++)
        {
            int sum = 0;
            for(int x : nums)
            {
                if(x & (1 << i))
                {
                    ++sum;
                }
            }
            sum %= 3; 
            if(sum == 1)
            {
                ans |= (1 << i);
            }
        }
        return ans;
    }
};

面试题 17.19. 消失的两个数字

//思路:将所有数字全部异或,转换为题目只出现了一次的数字3
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        unsigned int xor_all = 0;
        int n = nums.size();
        for(int x : nums)
        {
            xor_all ^= x;
        }
        for(int i = 1; i <= n+2; i++)
        {
            xor_all ^= i;
        }
        //计算最低位为1的位
        int lowbit = xor_all & (-xor_all);
        vector<int> ans(2);
        for(int x : nums)
        {
            if((lowbit & x) == 0)
            {
                ans[0] ^= x;
            }
            else
            {
                ans[1] ^= x;
            }
        }
        for(int i = 1; i <= n+2; i++)
        {
            if((lowbit & i) == 0)
            {
                ans[0] ^= i;
            }
            else
            {
                ans[1] ^= i;
            }
        }
        return ans;
    }
};

结束!


网站公告

今日签到

点亮在社区的每一天
去签到