1、题目名称
Gray Code(格雷码)
2、题目地址
https://leetcode.com/problems/gray-code/
3、题目内容
英文:
The gray code is a binary numeral system where two successive values differ in only one bit.
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
中文:
格雷码是一个二进制数字系统,在该系统中两个相邻的数字仅相差1个二进制位(比特)。
给出一个非负数字n,打印由n个二进制位组成的格雷码序列。格雷码序列的首个元素必须是0。
说明:
在n给定的情况下,按照上面定义(两个相邻数字仅相差1个二进制位),可以有多种格雷码的编码方案。比如n=2时,除了[0,1,3,2]外,[0,2,3,1]也是满足定义的,目前的OJ校验时只支持一种格雷码的编码方案,对此我们(出题人)表示抱歉。
4、解题方法
在题目说明中已经说明了“只支持一种格雷码的编码方案”,因此我们只需要搞清楚出题人希望我们实现的格雷码编码方案的生成规律就可以了。
我们先看几个不同位数的格雷码:
1)n=1时,序列为:0、1
2)n=2时,序列为:00、01、11、10
3)n=3时,序列为:000、001、011、010、110、111、101、100
4)n为任意自然数时,有如下一组规律
以0为开始,每次更改右数数字的位数,可以看做是中根遍历下图这颗二叉树
我们在实现的算法里并不需要用到树这个概念,这个图只是帮助理解我们算法中的递归。我们可以用位运算很轻易地获得这些位在二进制上的权(weight),并使用异或运算实现指定数位中0到1或1到0的转换,每次转换都会生成一个新的格雷码。
先在list中加入所有格雷码都需要添加的数字0,然后考虑生成长度为n的格雷码
生成长度为n的格雷码可以分为下面的步骤:
-
判断n的值,如果是0直接返回,如果是1直接执行第3步立即返回(这一步是递归出口)
-
生成长度为n-1的格雷码,将生成的数字依次插入list(这一步需要递归调用本步骤)
-
让右数第n位数字为1,即将当前数字异或上2的n-1次方,将这个数插入list
-
保证最左侧数字为1,再次生成长度n-1的格雷码,将生成的数字依次插入list(这一步需要递归调用本步骤)
需要注意的是,每次生成的格雷码,都会用作下一个格雷码的输入
一段实现此算法的Java代码为:
import java.util.ArrayList;
import java.util.List;
/**
* 功能说明:LeetCode 89 - Gray Code
* 开发人员:Tsybius2014
* 开发时间:2015年8月11日
*/
public class Solution {
//临时存储当前数字
int numCurr = 0;
//输出数组
ArrayList<Integer> arrayList;
/**
* 生成格雷码序列
* @param n 格雷码位数
* @return
*/
public List<Integer> grayCode(int n) {
if (n < 0) {
return null;
}
arrayList = new ArrayList<Integer>();
//任何位数的格雷码第一个数字都是0
numCurr = 0;
arrayList.add(numCurr);
//递归生成格雷码放入arrayList
getGrayCode(n);
return arrayList;
}
/**
* 递归将格雷码放入到arrayList中
* @param n 格雷码位数
*/
private void getGrayCode(int n) {
if (n == 0) {
return;
}
if (n == 1) {
numCurr = numCurr ^ 1;
arrayList.add(numCurr);
} else {
getGrayCode(n - 1);
numCurr = numCurr ^ (1 << n - 1);
arrayList.add(numCurr);
getGrayCode(n - 1);
}
}
}
END
来源:oschina
链接:https://my.oschina.net/u/1425762/blog/490934