首页 > 代码库 > [C++]LeetCode: 86 Gray Code (格雷码)

[C++]LeetCode: 86 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.

For example, given n = 2, return [0,1,3,2]. Its gray code sequence is:

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

Note:
For a given n, a gray code sequence is not uniquely defined.

For example, [0,2,3,1] is also a valid gray code sequence according to the above definition.

For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that.

Answer 1: 映射法

思路:我们通过对格雷码进行观察,发现格雷码具有映射关系。n位元的格雷码可以从n-1位元的格雷码以上下镜射后(一半顺序,一半逆序再加1<<n)加上新位元的方式快速的得到。我们从一个比特位的格雷码开始计算,直到得到N个比特位的格雷码。第一位是 0 + 1<<0, 0 + 1<<1.

技术分享

Attention:

1.2^n 可以表示为1<<n。

<span style="font-size:14px;"> curNum += (1 << i);</span>
2.当n取0时,返回{0},而不是空数组。

<span style="font-size:14px;">vector<int> ret{0};</span>
复杂度:O(N^2)

AC Code:

<span style="font-size:14px;">class Solution {
public:
    vector<int> grayCode(int n) {
        vector<int> ret{0};
        
        for(int i = 0; i < n; i++)
        {
            int curCnt = ret.size();
            //把当前数字按照逆序顺序添加到ret中
            while(curCnt)
            {
                curCnt--;
                int curNum = ret[curCnt];
                curNum += (1 << i);
                ret.push_back(curNum);
            }
        }
        
        return ret;
    }
};</span>

Answer 2: 二进制转格雷码

思路: 通过对二进制和格雷码的观察,我们得到计算公式:gray = (binary) xor (binary >> 1)。有篇文章有详细解释。

下面我们把二进制数和Gray码都写在下面,可以看到左边的数异或自身右移的结果就等于右边的数。

二进制数   Gray码
   000       000
   001       001
   010       011
   011       010
   100       110
   101       111
   110       101
   111       100


    从二进制数的角度看,“镜像”位置上的数即是对原数进行not运算后的结果。比如,第3个数010和倒数第3个数101的每一位都正好相反。假设这两个数分别为x和y,那么x xor (x shr 1)和y xor (y shr 1)的结果只有一点不同:后者的首位是1,前者的首位是0。而这正好是Gray码的生成方法。这就说明了,Gray码的第n个数确实是n xor (n shr 1)。

Attention:

1. 1 << n位,比特位为n+1位,正好表示n位二进制数+1,如三位二进制最大为7, 1<<3 = 8. 所以可以作为循环条件得到,我们要求的数的范围。

<span style="font-size:14px;">for(int i = 0; i < num; i++)</span>

AC Code:

<span style="font-size:14px;">class Solution {
public:
    vector<int> grayCode(int n) {
        int num = 1 << n;
        vector<int> ret;
        ret.reserve(num);
        
        for(int i = 0; i < num; i++)
        {
            ret.push_back(i ^ (i >> 1));
        }
        
        return ret;
    }
};</span>



[C++]LeetCode: 86 Gray Code (格雷码)