格雷码是一种二进制编码系统,如果任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code)。
给定一个非负整数n,表示代码的位数,打印格雷码的序列。格雷码序列必须以0开头。
例如:给定n=2,返回[0,1,3,2]. 格雷码的序列为:
00 - 0 01 - 1 11 - 3 10 - 2注意:
- 对于一个给定的n,格雷码的序列不一定是唯一的,
- 例如:根据题目描述,[0,2,3,1]也是一个有效的格雷码序列
00 - 0 01 - 1 11 - 3 10 - 2注意:
2
[0,1,3,2]
//随着n变大,前面的数不用动,后面的数倒着拿出来再在首部加1即可 class Solution { public: vector<int> grayCode(int n) { vector<int> result; result.push_back(0); for (int i = 0; i < n; i++) { const int hight_bit = 1 << i; for (int j = result.size() - 1; j >= 0; j--) //第二遍反着遍历,形成对称 result.push_back(hight_bit | result[j]); } return result; } };
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> result(pow(2,n));
for (int i=1;i<=n;++i)
{
int size = 1<<i;
int flag = 1<<(i-1);
int index = 0;
for (int j=size-1;2*j>=size;--j)
{
result[j] = result[index++]|flag; //左部插入1
}
}
return result;
}
};
当n=1时,为[0,1]
当n=2时,为[00,01,11,10]
当n=3时,为[000,001,011,010,110,111,101,100]
由此可以看出新的序列其实是在前面序列基础上插入新的值
其中前半部分的数值不变,后半部分的数值为上个序列中每个元素第n个位变1,逆向插入
这道题难在找 dp 方程 先看n=2 (00, 01, 11, 10) n = 3 ((000, 001, 011, 010), (100,101,111,110)) 以此类推, n=k时,就是在n=k-1的前面加上0或者1,然后使得数据扩大2倍 DP转移方程如下: dp[k] = dp[k-1] | 1<<n 其中 2^(n-1)=<k<2^n class Solution { public: vector<int> grayCode(int n) { vector<int> res(1,0); for(int i=0; i<n;i++){ for(int j=res.size()-1; j>=0; j--){ res.push_back(res[j]|1<<i); } } return res; } };
/* *规律是,后面每一个list的元素等于前面list顺序遍历的结果在每个元素前面+“0”,再逆序遍历 *每个元素前面+"1",可以先存储string格式方便处理,最后转换再返回int的集合 *就可以用动态规划解决了。 */ public ArrayList<Integer> grayCode(int n) { ArrayList<Integer> list=new ArrayList<>(); ArrayList<String> pre=new ArrayList<>(); if(n==0) { list.add(0); return list; } pre.add("0"); pre.add("1"); ArrayList<String> now; for(int i=2;i<=n;i++) { now=new ArrayList<>(); for(int j=0;j<pre.size();j++) { String str = "0"+pre.get(j); now.add(str); } for(int j=pre.size()-1;j>=0;j--) { String str = "1"+pre.get(j); now.add(str); } pre=now; } for(int i=0;i<pre.size();i++) { int num=getNum(pre.get(i)); list.add(num); } return list; } public int getNum(String str) { char[] array=str.toCharArray(); int i=0; int res=0; while(i<array.length) { if(array[i]=='1') { res+=Math.pow(2, array.length-1-i); } i++; } return res; }
class Solution { public: /** n = 0: 0 n = 1: 0, 1 n = 2: 00, 01, 11, 10 (0, 1, 3, 2) n = 3: 000, 001, 011, 010, 110, 111, 101, 100 (0, 1, 3, 2, 6, 7, 5, 4) */ /// 推广:n = i的gray code的前一半包括了n = i-1的所有gray code,而后一半则为前一半逆序后加上2^(i-1)。 vector<int> grayCode(int n) { vector<int> res; res.push_back(0); int inc = 1; for(int i=1;i<=n;i++) { for(int j=res.size()-1;j>=0;j--) res.push_back(res[j]+inc); inc <<= 1; } return res; } };
/*递归 先顺序往下在高位加0 再逆序往上在高位加1 组成的新排列满足要求 */
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> grayCode(int n) {
ArrayList<Integer> result = new ArrayList<>();
if (n < 0)
return result;
if (n == 0) {
result.add(0);
return result;
}
result.add(0);
result.add(1);
for (int i = 2; i <= n; i++) {
int size = result.size();
for (int j = size - 1; j >= 0; j--) {
result.add(result.get(j) + (1<<(i-1)));
}
}
return result;
}
}
/*给定n,返回n位格雷码序列。例如:n=2,返回[0(00), 1(01), 3(11), 2(10)] *n=1 返回 0 1 *n=2 返回 0 1 3 2 *n=3 返回 0 1 3 2 6 7 5 4 *观察规律:3=1+2,2=0+2; 6=2+4,7=3+4,5=1+4,4=0+4 */ import java.util.*; public class Solution { public ArrayList<Integer> grayCode(int n) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(0); if(n == 0) return list; list.add(1); if(n == 1) return list; for(int i = 1;i < n;i ++) { //循环次数 int size = list.size(); int increase = (int)Math.pow(2, i); //增量 for(int j = size - 1;j >= 0;j --) { list.add(list.get(j) + increase); } } return list; } }
class Solution: def grayCode(self , n ): array=[0] a=[] for i in range(1,n+1): a=reversed(array) a=list(a) for j in range(len(a)): a[j]+=2**(i-1) array+=a return array
这道题目可以用普通的循环来做,也可以用动态规划来做,相比起来动态规划的思路更加清晰,代码逻辑更加紧密。
当n为1时,输出0,1,n为2时,输出00,01,11,10,当n为3时,输出00,01,11,10,110,111,101,100。
// // Created by jt on 2020/8/25. // class Solution { public: /** * * @param n int整型 * @return int整型vector */ vector<int> grayCode(int n) { // write code here vector<int> res(1, 0); for (int i = 0; i < n; ++i) { int topBit = 1 << i; for (int j = res.size() - 1; j >= 0; --j) { res.push_back(topBit | res[j]); } } return res; } };
class Solution { public: vector<int> grayCode(int n) { vector<int>res; res.push_back(0); if(n<1)return res; for(int i=0;i<n;i++) { int size=res.size(); int highbit=1<<i; for(int j=size-1;j>=0;j--) { res.push_back(res[j]|(highbit)); } } return res; } };很巧妙的题,难在递推规律
import java.util.ArrayList; public class Solution { public ArrayList<Integer> grayCode(int n) { ArrayList<Integer> list = new ArrayList<>(); list.add(0); int head = 1; for(int i=1;i<=n;i++){ for(int j=list.size()-1;j>=0;j--){ list.add(head+list.get(j)); //把n-1位的格雷码从后往前把1插到第一位,并加到list //加上原来的n-1位的格雷码就成为了n位的格雷码 } head <<= 1; } return list; } } //参考了leetcode的第一个题解