格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。
给定一个代表编码总位数的非负整数 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<int> grayCode(int n) {
vector<int> 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