题目来源:https://leetcode-cn.com/problems/gray-code/
思路原著:https://leetcode-cn.com/u/zzpig/
格雷编码:https://baike.baidu.com/item/%E6%A0%BC%E9%9B%B7%E7%A0%81/6510858
题目
n位格雷码序列是一个由2n个整数组成的序列,其中:
- 每个整数都在范围[0,2n-1]内(含0和2n-1)
- 第一个整数是0
- 一个整数在序列中出现不超过一次
- 每对相邻整数的二进制表示恰好一位不同,且
- 第一个和最后一个整数的二进制表示恰好一位不同
给你一个整数n,返回任一有效的n位格雷码序列。
示例
输入: n=2
输出:[0,1,3,2]
解题思路
首先是发现规律:剔除掉首位二进制码,格雷编码的前半段与后半段完全相反。而首位的区别也仅仅是前半段为0,后半段为1。于是开始分析思路:
如图,首先在List中初始化首位为0,则其二进制表示方式为 0000 。
此时List中的值为:0000
定义一个head,用来存放待相加的值,定为1,因为接下来要0000改变成0001。
在list中添加head与list中所有值逆序相加的结果,譬如现在:List中只有0000,List逆序后也是0000,将head相加,值为0001,将0001添加到list中。
此时List中的值为:0000,0001
然后让head位运算左移一位,从0001变成0010。
在list中添加head与list中所有值逆序相加的结果,譬如现在:List中有0000和0001,List逆序后是0001和0000,将head相加,值分别为0011,0010,将这两个值add到List中。
此时List中的值为:0000,0001,0011,0010
然后让head位运算左移一位,从0010变成0100。
在list中添加head与list中所有值逆序相加的结果,譬如现在:List中有0000,0001,0011,0010,List逆序后是0010,0011,0001,0000,将head相加,值分别为0110,0111,0101,0100,将这四个值add到List中。
此时List中的值为:0000,0001,0011,0010,0110,0111,0101,0100
然后让head位运算左移一位,从0100变成1000。
重复上述操作,得到相加后的值:1100,1101,1111,1110,1010,1011,1001,1000,将该8个值add到List中。
此时便得到了n=4时的grayCode,返回这个List即可。
代码实现
public static List<Integer> grayCode(int n) {
//创建List用于存储结果
List<Integer> res = new ArrayList<>();
//先向List中添加0
res.add(0);
//如果n=0,那么此时只含有1个0的res就是所需格雷编码,无需进行任何操作
if (n != 0)
//n=4,表示格雷码为4位,head从二进制0001开始 移动到二进制1000一共需要移动3次
for (int i = 0, head = 1; i < n; i++) {
//将head与当前List中所有的值逆序相加并add到List中
for (int j = res.size() - 1; j >= 0; j--)
res.add(head + res.get(j));
//逆序相加完毕,head位运算左移1位
head = head << 1;
}
//返回计算后的结果
return res;
}
执行用时:7 ms, 在所有 Java 提交中击败了66.30%的用户
内存消耗:45.8 MB, 在所有 Java 提交中击败了21.12%的用户