【位运算】

前言

        没有
       今日份知识点:位运算
        今天是需要进行位运算,但是感觉更像考数学。

一、题目

题目 难度
868. 二进制间距 ⭐️
1734. 解码异或后的排列 ⭐️
89. 格雷编码 ⭐️
1238. 循环码排列 ⭐️

二、算法思路

1、二进制间距

        (1)【模拟】如果二进制的 n 的最低位为 1,那么判断是否是第一个,不是则更新答案;随后更新 pos,记录上一个 1 的位置。
        时间复杂度: O ( log ⁡ n ) O(\log{n}) O(logn)

class Solution {
    
    
public:
    int binaryGap(int n) {
    
    
        int ans = 0, pos = -1;
        for (int i = 0; n; ++ i) {
    
    
            if (n & 1) {
    
    
                if (pos != -1) ans = max(ans, i - pos);
                pos = i;
            }
            n >>= 1;
        }
        return ans;
    }
};

        (2)【二进制位模拟】int 总共有 32 位,判断每一位是否为 1,如果不是则跳过;是,判断是否第一个,不是则更新答案,然后更新 pos 记录当前 1 的位置。
        时间复杂度: O ( 32 ) O(32) O(32)

class Solution {
    
    
public:
    int binaryGap(int n) {
    
    
        int ans = 0, pos = -1;
        for (int i = 31; i >= 0; -- i) {
    
    
            if (((n >> i) & 1) == 1) {
    
    
                if (pos != -1) ans = max(ans, pos - i);
                pos = i;
            }
        }
        return ans;
    }
};

2、解码异或后的排列

        (1)【模拟】有两个重要的条件,原数组是前 n 个数的排列、加密数组的长度是 n - 1。那么根据 异或 异或 异或 的特性,我们可以先求从 1 − n 1-n 1n 的异或结果,然后根据 encoded 数组的特点,长度为奇数并且是元素组相邻两个元素异或的结果;我们对 encoded 数组间隔一个元素做异或操作,然后我们可以得到第一个元素或者最后一个元素的的值,最后根据 encoded 的特性依次还原原数组。
        时间复杂度: O ( n ) O(n) O(n)

class Solution {
    
    
public:
    vector<int> decode(vector<int>& encoded) {
    
    
        int total = 0;
        for (int i = 1; i <= encoded.size() + 1; ++ i) total ^= i;
        int old = 0;
        for (int i = 1; i < encoded.size(); i += 2) old ^= encoded[i];
        vector<int> ans(encoded.size() + 1);
        ans[0] = total ^ old;
        for (int i = 1; i <= encoded.size(); ++ i) {
    
    
            ans[i] = ans[i - 1] ^ encoded[i - 1];
        }
        return ans;
    }
};

3、格雷编码

        (1)【对称生成】对于答案数组,将其翻转后+1的数组拼接到一起,而原数组则全体 左移一位。对于最后一位,加1 前与第一位是一样的,+1 后与最后一位只有1位差别。
        时间复杂度: O ( n ) O(n) O(n)

class Solution {
    
    
public:
    vector<int> grayCode(int n) {
    
    
        vector<int> ans;
        ans.push_back(0);
        while (n -- > 0) {
    
    
            int m = ans.size();
            for (int i = m - 1; i >= 0; -- i) {
    
    
                ans[i] <<= 1;
                ans.push_back(ans[i] + 1);
            }
        }
        return ans;
    }
};

4、循环码排列

        (1)【对称生成】根据异或的特性,最终的答案数组全都异或上同一个数,得到的结果仍然符合条件,那么取一个 x,使 start ^ x = 0,即 x = start ^ 0,这样我们可是使用第3题的方法生成格雷码,然后让数组全部元素都乘一个 x
        时间复杂度: O ( n ) O(n) O(n)

class Solution {
    
    
public:
    vector<int> circularPermutation(int n, int start) {
    
    
        vector<int> ans = {
    
    0, 1};
        while (-- n > 0) {
    
    
            int t = ans.size();
            for (int i = t - 1; i >= 0; -- i) {
    
    
                ans[i] <<= 1;
                ans.push_back(ans[i] + 1);
            }
        }
        int x = start ^ ans[0];
        for (auto& u: ans) {
    
    
            u ^= x;
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/mumuynsi/article/details/125214426