剑指offer——Day22 位运算(中等)

Day22 2023.2.4 位运算(中等)

剑指offer 56 - Ⅰ. 数组中数字出现的次数

自己实现

就直接结合set进行遍历,然后出现重复就从set里面删除掉,最后就能得到只包含出现过一次的set

代码如下:

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        vector<int> res;
        set<int> s;
        for(int i=0;i<nums.size();i++){
            auto pos = s.find(nums[i]);
            if(pos==s.end())s.insert(nums[i]);
            else{
                s.erase(pos);
            }
        }
        for(auto i=s.begin();i!=s.end();i++)res.push_back(*i);
        return res;
    }
};

代码表现

时间花费有点太多了,看看题解

题解

首先有一个关于异或运算的使用性质

通过异或的这个性质,可以对整个数组进行遍历异或,结果会得到x^y

然后通过用一个比特位的1来循环左移找到x^y不等于0的那一个比特位(即x和y不同的那一个比特位)

然后可以根据这个比特位将原来的数组划分为两个子数组再来遍历验证

参考题解思路自己写的代码如下:

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int x=0,y;
        for(int i=0;i<nums.size();i++){
            x^=nums[i];
        }
        int m=1;
        while((x&m)==0){
            m<<=1;
        }
        x=0,y=0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]&m)x^=nums[i];
            else y^=nums[i];
        }
        return vector<int> {x,y};
    }
};

代码表现

hint

  • set的遍历是for(set<int>::iterator it=s.begin();it!=s.end();it++)判断条件是!=而不能写成<
  • &的优先级比==要低,所以如果要对&的结果进行条件判断的话要打括号!
  • 收获了一种新的异或的用法

剑指offer 56 - Ⅱ. 数组中数字出现的次数Ⅱ

自己实现

虽然收获了上一题的思路,但是三个数字相同的话就不能再使用异或了,直接看答案了

题解

方法一:有限状态自动机

大概理解但具体的代码理论支撑形成比较困难

具体可见K神题解

方法二:遍历统计

同样看K神题解,这个还没来得及看

方法一的代码如下:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ones = 0, twos = 0;
        for(int num : nums){
            ones = ones ^ num & (~twos);
            twos = twos ^ num & (~ones);
        }
        return ones;
    }
};

代码表现

hint:

  • 这个位运算吧,可以算作一种很奇特的方法,比如在有偶数个重复数字的情况下,可以用遍历异或来快速筛选出这些数。但是位运算对应的用法和使用场景需要多积累,毕竟要多转几个弯,代码优化的时候应该能用上。
posted @ 2023-02-04 13:56  神鹏佐佑  阅读(23)  评论(0)    收藏  举报