前言
没有
今日份知识点:位运算
今天是需要进行位运算,但是感觉更像考数学。
一、题目
题目 | 难度 |
---|---|
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 1−n 的异或结果,然后根据 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;
}
};