「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战」。
题目
链接:leetcode-cn.com/problems/gr…
n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:
- 每个整数都在范围
[0, 2n - 1]内(含0和2n - 1) - 第一个整数是
0 - 一个整数在序列中出现 不超过一次
- 每对 相邻 整数的二进制表示 恰好一位不同 ,且
- 第一个 和 最后一个 整数的二进制表示 恰好一位不同
给你一个整数 n ,返回任一有效的 n 位格雷码序列 。
示例 1:
输入: n = 2 输出: [0,1,3,2] 解释: [0,1,3,2] 的二进制表示是 [00,01,11,10] 。
- 00 和 0_1_ 有一位不同
- _0_1 和 _1_1 有一位不同
- 1_1_ 和 1_0_ 有一位不同
- _1_0 和 _0_0 有一位不同 [0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。
- _0_0 和 _1_0 有一位不同
- 1_0_ 和 1_1_ 有一位不同
- _1_1 和 _0_1 有一位不同
- 0_1_ 和 0_0_ 有一位不同
示例 2:
输入: n = 1 输出: [0,1]
提示:
1 <= n <= 16
解题思路
格雷编码 相邻两个数的二进制码只能有一位不相同
接下来,找规律,因为这道题很明显要用数学的方法来解决
当n = 0 0
当n = 1 0 | 1
当n = 2 00 01 | 11 10
当n = 3 000 001 011 010 | 110 111 101 100
......
看出规律没
我专门用了一条竖线划分左右两边
根据竖线对称的元素只在最高位相差一个1 转换为10进制就是 竖线左边元素 + 2的n-1次方 = 竖线右边元素
还有一个规律就是每次镜子(竖线)的左边都是上一轮的元素,只不过二进制码在最前面多出一个0而已,但多出的这个0其实并不影响它原本的十进制数,所以我们的代码只需要在十进制环境下操作就可以了,并不需要转换为二进制
最后说一下求镜像右边的元素,它的求法其实就是从尾开始遍历上一轮的元素,镜像右边的每一个值就是上一轮元素加上2的n-1次方就可以了,代码用的递推,可以优化空间复杂度,ans表示n - 1的元素,求n位元素的话就可以应用我上面说的镜像求法,pre用来表示2的n - 1次方,每轮乘2就可以即pre<<=1,用位运算速度会比用*2快一些
时间复杂度O(n*2^n)
空间复杂度O(1) 假如存储答案的数组不计入额外空间的话
代码
var grayCode = function(n) {
let ans = [0];
let pre = 1;
for(let i = 0;i<n;i++){
for(let j = ans.length - 1;j>=0;j--){
ans.push(pre + ans[j]);
}
pre <<= 1;
}
return ans;
};