LeetCode(89):格雷编码
Medium!
题目描述:
格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。
给定一个代表编码总位数的非负整数 n,打印格雷码序列。格雷码序列必须以 0 开头。
例如,给定 n = 2,返回 [0,1,3,2]。其格雷编码是:
00 - 0
01 - 1
11 - 3
10 - 2
说明:
对于给定的 n,其格雷编码的顺序并不唯一。
例如 [0,2,3,1] 也是一个有效的格雷编码顺序。
解题思路:
格雷码是一种循环二进制单位距离码,主要特点是两个相邻数的代码只有一位二进制数不同的编码,格雷码的处理主要是位操作 Bit Operation,LeetCode中关于位操作的题也挺常见,比如 Repeated DNA Sequences 求重复的DNA序列,Single Number 单独的数字, 和 Single Number II 单独的数字之二 等等。三位的格雷码和二进制数如下:

Int Grey Code Binary
0 000 000
1 001 001
2 011 010
3 010 011
4 110 100
5 111 101
6 101 110
7 100 111

其实这道题还有多种解法。首先来看一种最简单的,是用到格雷码和二进制数之间的相互转化,可参见http://www.cnblogs.com/grandyang/p/4315607.html,明白了转换方法后,这道题完全没有难度。
C++解法一:
// Binary to grey code
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res;
for (int i = ; i < pow(,n); ++i) {
res.push_back((i >> ) ^ i);
}
return res;
}
};
然后我们来看看其他的解法,参考维基百科上关于格雷码的性质,有一条是说镜面排列(http://zh.wikipedia.org/wiki/%E6%A0%BC%E9%9B%B7%E7%A0%81)的,n位元的格雷码可以从n-1位元的格雷码以上下镜射后加上新位元的方式快速的得到,如下图所示一般。

有了这条性质,我们很容易的写出代码如下。
C++解法二:
// Mirror arrangement
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res{};
for (int i = ; i < n; ++i) {
int size = res.size();
for (int j = size - ; j >= ; --j) {
res.push_back(res[j] | ( << i));
}
}
return res;
}
};
维基百科上还有一条格雷码的性质是直接排列(http://zh.wikipedia.org/wiki/%E6%A0%BC%E9%9B%B7%E7%A0%81),以二进制为0值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反复,即可排列出n个位元的格雷码。根据这条性质也可以写出代码,不过相比前面的略微复杂,代码如下:
0 0 0
0 0 
0  1
0 1 
 1 0
1 1 
1  1
1 0
C++解法三:
// Direct arrangement
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res{};
int len = pow(, n);
for (int i = ; i < len; ++i) {
int pre = res.back();
if (i % == ) {
pre = (pre & (len - )) | ((~pre) & );
} else {
int cnt = , t = pre;
while ((t & ) != ) {
++cnt;
t >>= ;
}
if ((pre & ( << cnt)) == ) pre |= ( << cnt);
else pre &= ~( << cnt);
}
res.push_back(pre);
}
return res;
}
};
上面三种解法都需要事先了解格雷码及其性质,假如我们之前并没有接触过格雷码,那么我们其实也可以用比较笨的方法来找出结果,比如下面这种方法用到了一个set来保存已经产生的结果,我们从0开始,遍历其二进制每一位,对其取反,然后看其是否在set中出现过,如果没有,我们将其加入set和结果res中,然后再对这个数的每一位进行遍历,以此类推就可以找出所有的格雷码了。
C++解法四:
 class Solution {
 public:
     vector<int> grayCode(int n) {
         vector<int> res;
         unordered_set<int> s;
         helper(n, s, , res);
         return res;
     }
     void helper(int n, unordered_set<int>& s, int out, vector<int>& res) {
         if (!s.count(out)) {
             s.insert(out);
             res.push_back(out);
         }
         for (int i = ; i < n; ++i) {
             int t = out;
             if ((t & ( << i)) == ) t |= ( << i);
             else t &= ~( << i);
             if (s.count(t)) continue;
             helper(n, s, t, res);
             break;
         }
     }
 };
既然递归方法可以实现,那么就有对应的迭代的写法,当然需要用stack来辅助。
C++解法五:
 class Solution {
 public:
     vector<int> grayCode(int n) {
         vector<int> res{};
         unordered_set<int> s;
         stack<int> st;
         st.push();
         s.insert();
         while (!st.empty()) {
             int t = st.top(); st.pop();
             for (int i = ; i < n; ++i) {
                 int k = t;
                 if ((k & ( << i)) == ) k |= ( << i);
                 else k &= ~( << i);
                 if (s.count(k)) continue;
                 s.insert(k);
                 st.push(k);
                 res.push_back(k);
                 break;
             }
         }
         return res;
     }
 };
LeetCode(89):格雷编码的更多相关文章
- Java实现 LeetCode 89 格雷编码
		89. 格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 示例 1: 输 ... 
- Leetcode 89.格雷编码
		格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 示例 1: 输入: 2 ... 
- leetcode刷题-89格雷编码
		题目 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.即使有多个不同答案,你也只需要返回其中一种. 格雷编码序列 ... 
- leetcode(js)算法89之格雷编码
		格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头 示例 1: 输入: 2 输出: [ ... 
- LeetCode刷题笔记-贪心法-格雷编码
		题目描述: 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 来源:力扣(Leet ... 
- [Swift]LeetCode89. 格雷编码 | Gray Code
		The gray code is a binary numeral system where two successive values differ in only one bit. Given a ... 
- 089 Gray Code 格雷编码
		格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异.给定一个代表编码总位数的非负整数 n,打印格雷码序列.格雷码序列必须以0开头.例如, 给定 n = 2, 返回 [0,1,3 ... 
- lintcode:格雷编码
		格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个二进制的差异. 给定一个非负整数 n ,表示该代码中所有二进制的总数,请找出其格雷编码顺序.一个格雷编码顺序必须以 0 开始, ... 
- 【leetcode-89  动态规划】 格雷编码
		( 中等难度题(×) -背答案题(√) ) 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 ... 
随机推荐
- python加密(MD5)
			# import hashlib # # 1. 创建一个MD5对象 # obj = hashlib.md5(b"flkjsdalkfjklasdjfklasjkflasdjklfasdjfl ... 
- vue的Http请求拦截及处理
			/*公共加载遮罩*/ (function($) { $.fn.jqLoading = function(option) { var defaultVal = { backgroudColor : &q ... 
- java创建对象 的初始化顺序
			java创建对象 的初始化顺序 1.初始化块 初始化块通常写在类的构造方法之前,由花括号括起来,通常包含对成员属性进行初始化的语句: 初始化块分为instance初始化块和static初始化块,初始化 ... 
- C - Kite URAL - 1963 (几何+四边形判断对称轴)
			题目链接:https://cn.vjudge.net/problem/URAL-1963 题目大意:给你一个四边形的n个点,让你判断对称点的个数(对称轴的个数*2). 具体思路:感谢qyn的讲解,具体 ... 
- response的字节流和字符流输入的区别和问题--02-response的outputStream输出数据的问题.avi
			02-response的outputStream输出数据的问题.avi; [字节流] 用meta标签 第一段原始代码:写错: 03-response的Writer输出数据的问题.avi;[字符流输出] ... 
- 关于Sublime Text 3的几个问题总结
			问题1:Sublime Text 3的注册码. 注册码网上搜有很多,所以可以去网上找.我现在给的可能以后就不能用了,而且我也是网上找的... 这个现在最新版本是可用的. —– BEGIN LICENS ... 
- 同步&异步+阻塞&非阻塞(理解)
			0 - 同步&异步 同步和异步关注的是消息通信机制. 0.1 - 同步 由“调用者”主动等待这个“调用”结果.即是,发出一个“调用”时,在没有得到结果之前,该“调用”不返回,一旦调用返回,则得 ... 
- 2017-2018-2 20165221实验二《Java面向对象程序设计》实验报告
			JAVA实验二报告 课程:Java程序设计 姓名:谭笑 学号:20165221 实验时间:2018.4.13--2018.4.15 实验2--1 实验内容 实现百分制成绩转成"优.良.中.及 ... 
- vim设置行号
			vim打开文件后在底行模式下输入:set nu可以在文件每行开头显示对应的行数: 若想vim打开文件默认显示行数,执行:vim /etc/vimrc,在打开的文件末尾添上:set nu,保存退出即可! 
- zookeeper安装教程
			zookeeper 一.单机安装 1.1 下载 1.2 安装 1.3 配置 1.4 启动和停止 二.伪集群模式 2.1 zookeeper1配置 2.2 zookeeper2配置 2.3 zooke ... 
