leetcode--89 格雷编码

格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。

给定一个代表编码总位数的非负整数 n,打印格雷码序列。格雷码序列必须以 0 开头。

例如,给定 n = 2,返回 [0,1,3,2]。其格雷编码是:

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

说明:

对于给定的 n,其格雷编码的顺序并不唯一。

例如 [0,2,3,1] 也是一个有效的格雷编码顺序。




题意很好理解,但相关背景和知识则完全不懂,于是跑去wiki上了解了一下,发现有多种解法,下面列出两种。

直接排列法:

在二进制下,以0为第零项,第一项为前一项改变最右边的位元得到,第二项为改变前一项从右起到第一个为1的位的左边位元得到,第三项重复第一项的操作,第四项重复第二项的操作。即奇偶分别对应一种操作,但都是对其前一位。因此我们要先把0放进去,后边的数由前边的数递推得到(就像斐波那契数列那样)。

实现代码:

// Direct arrangement 
class Solution {
public:
    vector<int> grayCode(int n) {
        vector<int> res{0};
        int len = pow(2, n);
        for (int i = 1; i < len; ++i) {
            int pre = res.back();
            if (i % 2 == 1) {
                pre = (pre & (len - 2)) | ((~pre) & 1);
            } else {
                int cnt = 1, t = pre;
                while ((t & 1) != 1) {
                    ++cnt;
                    t >>= 1;
                }
                if ((pre & (1 << cnt)) == 0) pre |= (1 << cnt);
                else pre &= ~(1 << cnt);
            }
            res.push_back(pre);
        }
        return res;
    }
};



镜像构造法:


看起来让人有点摸不着边,但在纸上照着画一遍就好理解一些了。图中的一道道长度不等的"横线"代表镜面,上下关于其成镜面对称分布,以从n=2到n=3的变换为例,我们已经得出了4个二进制数,即n=2是已知的,现在加一个镜子,再添加一些对称的数(相当于复制,但对称),之后我们把镜面上方的每个数的在最其左边补一个0,再在镜面下方的每个数的最左边补一个1,就得到了下一种情况,以此类推。当然每个数组共有2的n次方个元素,和镜面构造在数量上的特点也一致。实现代码:

// Mirror arrangement
class Solution {
public:
    vector grayCode(int n) {
        vector res{0};
        for (int i = 0; i < n; ++i) {
            int size = res.size();
            for (int j = size - 1; j >= 0; --j) {
                res.push_back(res[j] | (1 << i));
            }
        }
        return res;
    }
};

不过我看不懂关于push_back的那个语句,所以这个方法看不太明白。。


补充:该方法的核心和leetcode上关于集合的那道是一样的!


参考资料:

https://en.wikipedia.org/wiki/Gray_code

https://zh.wikipedia.org/wiki/格雷码

http://www.cnblogs.com/grandyang/p/4315649.html


你可能感兴趣的:(Leetcode)