题目链接
n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:
每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 1)
第一个整数是 0
一个整数在序列中出现 不超过一次
每对 相邻 整数的二进制表示 恰好一位不同 ,且
第一个 和 最后一个 整数的二进制表示 恰好一位不同
给你一个整数 n ,返回任一有效的 n 位格雷码序列 。
我的代码
public IList<int> GrayCode(int n)
{
List<int> res = new List<int>();
res.Add(0);
int lens = (int)Math.Pow(2, n);
ValueTuple<int, bool, int[]>[] alls = new ValueTuple<int, bool, int[]>[lens];
myfun(n, alls);
alls[0].Item2 = true;
myfun2(n, alls, res);
return res;
}
public void myfun(int n, ValueTuple<int, bool, int[]>[] alls)
{
for (int i = 0; i < alls.Length; i++)
{
alls[i] = new ValueTuple<int, bool, int[]>(i, false, new int[n]);
string str = Convert.ToString(i, 2).PadLeft(n, '0');
for (int j = 0; j < n; j++)
{
char[] ch = str.ToCharArray();
ch[j] = ch[j] == '0' ? '1' : '0';
alls[i].Item3[j] = Convert.ToInt32(new string(ch), 2);
}
}
}
public bool myfun2(int n, ValueTuple<int, bool, int[]>[] alls, List<int> res)
{
if (res.Count == alls.Length) return true;
int index = res[res.Count - 1];
bool isover = false;
for (int i = 0; i < n; i++)
{
int num = alls[index].Item3[i];
if (alls[num].Item2 == true) continue;
res.Add(num);
alls[num].Item2 = true;
isover= myfun2(n, alls, res);
if (isover == false)
{
res.RemoveAt(res.Count - 1);
alls[num].Item2 = false;
}
else return true;
}
return false;
}
代码思路
- 首先观察到每个数字的下一数字只可能有n个,分别是对应二进制中各个位上的一次取反。
- 然后根据数据结构领接矩阵的思想,深度递归构建的矩阵。
- 就算是算法本人,我也解释不了,为什么这么做,最后一个数字一定会和0满足格雷编码的条件。
- 更严谨的做法是,最后加上判断。
官方代码
public class Solution {
public IList<int> GrayCode(int n) {
IList<int> ret = new List<int>();
ret.Add(0);
for (int i = 1; i <= n; i++) {
int m = ret.Count;
for (int j = m - 1; j >= 0; j--) {
ret.Add(ret[j] | (1 << (i - 1)));
}
}
return ret;
}
}