Tag Archives: 格雷码

LeetCode Gray Code

89. Gray Code

The gray code is a binary numeral system where two successive values differ in only one bit.

Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.

Example 1:

Input: 2
Output: [0,1,3,2]
Explanation:
00 - 0
01 - 1
11 - 3
10 - 2

For a given n, a gray code sequence may not be uniquely defined.
For example, [0,2,3,1] is also a valid gray code sequence.

00 - 0
10 - 2
11 - 3
01 - 1

Example 2:

Input: 0
Output: [0]
Explanation: We define the gray code sequence to begin with 0.
             A gray code sequence of n has size = 2n, which for n = 0 the size is 20 = 1.
             Therefore, for n = 0 the gray code sequence is [0].

格雷码是这样一种编码:第一个数为0,后面每个数和前一个数在二进制位上只相差一位。现在给定二进制编码为n位,要求输出一串格雷码。
在不了解格雷码的情况下,可以单纯根据上面格雷码的定义来列出这一串格雷码,我们需要尝试依次翻转n位中的每一位,如果翻转之后得到的编码之前没有出现过,则翻转成功,接着进入下一次尝试,直到产生所有格雷码。
假设一个二进制数为x,则翻转其第i位之后的二进制数为(x&(~(1 << i))) | (~x)&(1 << i),还是有点复杂的。
这种思路可以用递归的方法实现,完整代码如下:

class Solution {
public:
    void work(vector<int>& ans, unordered_set<int>& codes, int gray, int n)
    {
        for (int i = 0; i < n; ++i) {
            int new_gray = (gray & (~(1 << i))) | (~gray) & (1 << i); // flip i-th bit
            if (codes.find(new_gray) == codes.end()) {
                codes.insert(new_gray);
                ans.push_back(new_gray);
                work(ans, codes, new_gray, n);
                break;
            }
        }
    }
    vector<int> grayCode(int n)
    {
        vector<int> ans = { 0 };
        if (n == 0)
            return ans;
        unordered_set<int> codes = { 0 };
        work(ans, codes, 0, n);
        return ans;
    }
};


本代码提交AC,用时6MS。
查看格雷码的维基百科,有好多种方法都可以生成格雷码序列,其中一种很有意思,可以根据二进制长度为n-1的格雷码序列生成二进制长度为n的格雷码序列,如下图所示,这种方法叫做镜射排列。

仔细观察会发现,n长的格雷码序列的前一半序列和n-1长的格雷码序列,在十进制数上是完全一样的,二进制数上也只是多了一个前导零;而后半序列是n-1长的格雷码序列镜面对称之后,加上一位前导1得到的。所以很容易可以写出镜射排列的代码:

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

本代码提交AC,用时3MS。