[LeetCode] Grey 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.

 

这道题是关于格雷码的,猛地一看感觉完全没接触过格雷码,但是看了维基百科后,隐约的感觉原来好像哪门可提到过,哎全还给老师了。这道题如果不了解格雷码,还真不太好做,幸亏脑补了维基百科,格雷码的处理主要是位操作 Bit Operation,LeetCode中关于位操作的题也挺常见,比如 Repeated DNA Sequences 求重复的DNA序列 Single Number 单独的数字, 和  Single Number II 单独的数字之二 等等。三位的格雷码和二进制数如下:

 

Int    Grey Code    Binary

 0      000        000

 1      001        001

 2      011        010

 3      010        011

 4      110        100

 5      111        101

 6      101        110

 7      100        111

 

其实这道题还有多种解法。首先来看一种最简单的,是用到格雷码和二进制数之间的相互转化,可参见我之前的博客 Convertion of grey code and binary 格雷码和二进制数之间的转换 ,明白了转换方法后,这道题完全没有难度,代码如下:

解法一:

// Binary to grey code

class Solution {

public:

    vector<int> grayCode(int n) {

        vector<int> res;

        for (int i = 0; i < pow(2,n); ++i) {

            res.push_back((i >> 1) ^ i);

        }

        return res;

    }

};

 

然后我们来看看其他的解法,参考维基百科上关于格雷码的性质,有一条是说镜面排列的,n位元的格雷码可以从n-1位元的格雷码以上下镜射后加上新位元的方式快速的得到,如下图所示一般。

有了这条性质,我们很容易的写出代码如下:

解法二:

// Mirror arrangement

class Solution {

public:

    vector<int> grayCode(int n) {

        vector<int> res;

        res.push_back(0);

        for (int i = 0; i < n; i++) {

            int highBit = 1 << i;

            int len = res.size();

            for (int j = len - 1; j >= 0; --j) {

                res.push_back(highBit + res[j]);

            }

        }

        return res;

    }

};

 

维基百科上还有一条格雷码的性质是直接排列,以二进制为0值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反复,即可排列出n个位元的格雷码。根据这条性质也可以写出代码,不过相比前面的略微复杂,代码如下:

解法三:

// Direct arrangement 

class Solution {

public:

    vector<int> grayCode(int n) {

        vector<int> res(1, 0);

        int len = pow(2, n);

        for (int i = 1; i < len; ++i) {

            int pre = res[i -1];

            if (i % 2 != 0) {

                res.push_back((pre & (len - 2)) | ((~pre) & 1));

            } else {

                int count = 0;

                while ((pre & 1) != 1) {

                    ++count;

                    pre = pre >> 1;

                }

                pre = pre >> 1;

                pre = (pre & (len - 2)) | ((~pre) & 1);

                pre = (pre << 1) | 1;

                res.push_back(pre << count);

            }

        }

        return res;

    }

};

 

LeetCode All in One 题目讲解汇总(持续更新中...)

你可能感兴趣的:(LeetCode)