·题目描述
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 和 01 有一位不同
- 01 和 11 有一位不同
- 11 和 10 有一位不同
- 10 和 00 有一位不同
[0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。
- 00 和 10 有一位不同
- 10 和 11 有一位不同
- 11 和 01 有一位不同
- 01 和 00 有一位不同
示例 2:
输入:n = 1
输出:[0,1]
·格雷编码的规律
格雷编码是n= 0 也就是编码数组nums = 【0】开始往上递增的。递增的规律有两个:
1.保持nums数组中前元素不变,在nums后端不断添加新元素。新元素的构成是在原始数组上逆序遍历,再在该元素的最高位添加一个1 ,在二进制中表述为
(ground.get(i) | size)
size = nums.size()
表示对nums列表中的第 i
个元素执行按位或操作,并且按位或操作的右操作数是 size
。
假设 nums 列表当前包含 [0, 1],并且 size 是 4。
对于 nums.get(0) = 0:
nums.get(0) | size 将会生成一个新的 Gray 码。
nums.get(0) 的二进制表示是 0000,size 的二进制表示是 0100。
将它们进行按位或运算:0000 | 0100,得到结果 0100,即 4。
对于 nums.get(1) = 1:
nums.get(1) | size 将会生成另一个新的 Gray 码。
nums.get(1) 的二进制表示是 0001,size 的二进制表示是 0100。
将它们进行按位或运算:0001 | 0100,得到结果 0101,即 5。
2.原始的nums元素全部左移并且后端添上0,在十进制中表示为×2的操作;然后采用逆序,nums的元素左移并且后端添加1,添加到nums后端。
例如
n = 1 时候 , nums = [0 , 1]
将0->00, 1 -> 10,并且逆序遍历1->11,0 ->01
所以n = 2 的时候, nums =[00, 01, 11, 10]
同理可得 ,n = 3 的时候, nums = [000,010,110,100 , 101,111,011,001]
java
import java.util.ArrayList;
import java.util.List;
class Solution {
List<Integer> ground = new ArrayList<>();
public List<Integer> grayCode(int n) {
ground.add(0);
backtrack(n);
return ground;
}
public void backtrack( int n) {
int size = ground.size();
if (size == (int) Math.pow(2,n)) return;
//构建方法1
for(int i = size - 1; i >= 0; i --){
int num = (ground.get(i) | size) ;
ground.add(num);
}
backtrack(n);
//构建方法2
for(int i = size - 1; i >= 0; i --){
int num = (ground.get(i) << 1) | 1 ;
ground.add(num);
}
for(int i = 0; i < size ; i ++){
ground.set(i , ground.get(i) * 2);
}
backtrack(n);
}
}
public class Main {
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.grayCode(3));
}
}