目录
一,格雷码
1,力扣 89. 格雷编码
n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:
每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 1)
第一个整数是 0
一个整数在序列中出现 不超过一次
每对 相邻 整数的二进制表示 恰好一位不同 ,且
第一个 和 最后一个 整数的二进制表示 恰好一位不同
给你一个整数 n ,返回任一有效的 n 位格雷码序列 。
示例 1:
输入:n = 2
输出:[0,1,3,2]
解释:
[0,1,3,2] 的二进制表示是 [00,01,11,10] 。
- 00 和 01 有一位不同
- 01 和 11 有一位不同
- 11 和 10 有一位不同
- 10 和 00 有一位不同
[0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。
- 00 和 10 有一位不同
- 10 和 11 有一位不同
- 11 和 01 有一位不同
- 01 和 00 有一位不同
示例 2:
输入:n = 1
输出:[0,1]
提示:
1 <= n <= 16
思路:
利用分治算法,由n位格雷码可以直接得到n+1位格雷码。
代码:
//翻转vector
template<typename T>
vector<T> frev(const vector<T>& v)
{
vector<T> ans;
ans.resize(v.size());
for (int i = 0; i < v.size(); i++)ans[i] = v[v.size() - 1 - i];
return ans;
}
//vector加一个数
template<typename T1, typename T2>
void fjia(vector<T1>& v, T2 n)
{
for (int i = v.size() - 1; i >= 0; i--)v[i] += n;
}
//2个vector拼接起来
template<typename T>
vector<T> join(const vector<T>& v1, const vector<T>& v2)
{
vector<T>ans(v1.size() + v2.size());
copy(v1.begin(), v1.end(), ans.begin());
copy(v2.begin(), v2.end(), ans.begin() + v1.size());
return ans;
}
class Solution {
public:
vector<int> grayCode(int n) {
if (n <= 0) {
return vector<int>(1);
}
vector<int> v = grayCode(n - 1);
vector<int> v2 = frev(v);
fjia(v2, 1 << n - 1);
return join(v, v2);
}
};
2,格雷码简介
上面的题目已经把格雷码的要求说的很清楚了,输出解释里面也提到了格雷码不是唯一的。
我上面代码得到的是最典型的格雷码(和上面图片内相同),一般格雷码默认指的就是这种。
对于典型格雷码,可以直接算出每个数的格雷码:
对于n位二进制数a1 a2 ... an,表示成n位格雷码g1 g2 ... gn,
则,这里的+表示异或
例如11的四位二进制是1011,则格雷码是1110,即14
用数学归纳法很容易证明这个规律是对的。
(1)二进制转格雷码
void gray(int n, int k)
{
vector<int>v;
for (int i = 0; i < k; i++) {
v.push_back(n % 2);
n /= 2;
}
v.push_back(0);
for (int i = k; i; i--)cout << (v[i] ^ v[i - 1]);
}
int main()
{
int n, k;
cin >> n >> k;
gray(n, k);
return 0;
}
输入:9 4
输出:1101 即9的四位格雷码
(2)格雷码转二进制
void grayToInt(int n, int k)
{
vector<int>v;
for (int i = 0; i < k; i++) {
v.push_back(n % 2);
n /= 2;
}
int tmp;
cout << (tmp = v[k - 1]);
for (int i = k - 2; i >= 0; i--)cout << (tmp = (v[i] ^ tmp));
}
int main()
{
int n, k;
cin >> n >> k;
grayToInt(n, k);
return 0;
}
输入:14 4
输出:1011 即四位格雷码14表示的是11
3,格雷码和九连环
九连环按照每个环在上面就是1在下面就是0编号,可以得到一个九位二进制数。
每次只能修改一位(一个环),最终的目标是变成000000000
神奇的是,九连环的最快解法(即没有无效操作,不考虑最后2个环一起操作)就是在从2^9-1到0的一个遍历。
grayToInt(511,9)的结果是101010101,即341,所以九连环需要341步。
也可以根据gray函数直接把九连环的步骤打出来:
void gray(int n, int k)
{
vector<int>v;
for (int i = 0; i < k; i++) {
v.push_back(n % 2);
n /= 2;
}
v.push_back(0);
for (int i = k; i; i--)cout << (v[i] ^ v[i - 1]);
cout << " ";
}
int main()
{
for (int n = 341; n >= 0; n--) {
gray(n, 9);
if (n % 5 == 0)cout << endl;
}
return 0;
}
输出:
111111111 111111110
111111010 111111011 111111001 111111000 111101000
111101001 111101011 111101010 111101110 111101111
111101101 111101100 111100100 111100101 111100111
111100110 111100010 111100011 111100001 111100000
110100000 110100001 110100011 110100010 110100110
110100111 110100101 110100100 110101100 110101101
110101111 110101110 110101010 110101011 110101001
110101000 110111000 110111001 110111011 110111010
110111110 110111111 110111101 110111100 110110100
110110101 110110111 110110110 110110010 110110011
110110001 110110000 110010000 110010001 110010011
110010010 110010110 110010111 110010101 110010100
110011100 110011101 110011111 110011110 110011010
110011011 110011001 110011000 110001000 110001001
110001011 110001010 110001110 110001111 110001101
110001100 110000100 110000101 110000111 110000110
110000010 110000011 110000001 110000000 010000000
010000001 010000011 010000010 010000110 010000111
010000101 010000100 010001100 010001101 010001111
010001110 010001010 010001011 010001001 010001000
010011000 010011001 010011011 010011010 010011110
010011111 010011101 010011100 010010100 010010101
010010111 010010110 010010010 010010011 010010001
010010000 010110000 010110001 010110011 010110010
010110110 010110111 010110101 010110100 010111100
010111101 010111111 010111110 010111010 010111011
010111001 010111000 010101000 010101001 010101011
010101010 010101110 010101111 010101101 010101100
010100100 010100101 010100111 010100110 010100010
010100011 010100001 010100000 011100000 011100001
011100011 011100010 011100110 011100111 011100101
011100100 011101100 011101101 011101111 011101110
011101010 011101011 011101001 011101000 011111000
011111001 011111011 011111010 011111110 011111111
011111101 011111100 011110100 011110101 011110111
011110110 011110010 011110011 011110001 011110000
011010000 011010001 011010011 011010010 011010110
011010111 011010101 011010100 011011100 011011101
011011111 011011110 011011010 011011011 011011001
011011000 011001000 011001001 011001011 011001010
011001110 011001111 011001101 011001100 011000100
011000101 011000111 011000110 011000010 011000011
011000001 011000000 001000000 001000001 001000011
001000010 001000110 001000111 001000101 001000100
001001100 001001101 001001111 001001110 001001010
001001011 001001001 001001000 001011000 001011001
001011011 001011010 001011110 001011111 001011101
001011100 001010100 001010101 001010111 001010110
001010010 001010011 001010001 001010000 001110000
001110001 001110011 001110010 001110110 001110111
001110101 001110100 001111100 001111101 001111111
001111110 001111010 001111011 001111001 001111000
001101000 001101001 001101011 001101010 001101110
001101111 001101101 001101100 001100100 001100101
001100111 001100110 001100010 001100011 001100001
001100000 000100000 000100001 000100011 000100010
000100110 000100111 000100101 000100100 000101100
000101101 000101111 000101110 000101010 000101011
000101001 000101000 000111000 000111001 000111011
000111010 000111110 000111111 000111101 000111100
000110100 000110101 000110111 000110110 000110010
000110011 000110001 000110000 000010000 000010001
000010011 000010010 000010110 000010111 000010101
000010100 000011100 000011101 000011111 000011110
000011010 000011011 000011001 000011000 000001000
000001001 000001011 000001010 000001110 000001111
000001101 000001100 000000100 000000101 000000111
000000110 000000010 000000011 000000001 000000000