89. Gray Code
问题:
给定二进制数的位数n,从0开始,每次反转一位,最终遍历完所有位反转。按顺序加入结果res。
Example 1: Input: n = 2 Output: [0,1,3,2] Explanation: 00 - 0 01 - 1 11 - 3 10 - 2 [0,2,3,1] is also a valid gray code sequence. 00 - 0 10 - 2 11 - 3 01 - 1 Example 2: Input: n = 1 Output: [0,1] Constraints: 0 <= n <= 15
解法一:Backtracking(回溯算法)
对每一位pos,
- 初始状态0 backtrack_1
- 反转pos位 flip[pos]
- pos位0->1 backtrack_2
逻辑参考图:(✅ 为一层调用)
代码参考:
1 class Solution { 2 public: 3 void backtrack(vector<int>& res, bitset<32>& bit, int n, int pos) { 4 if(pos==n) { 5 res.push_back(bit.to_ullong()); 6 return; 7 } 8 backtrack(res, bit, n, pos+1); 9 bit.flip(pos); 10 backtrack(res, bit, n, pos+1); 11 return; 12 } 13 vector<int> grayCode(int n) { 14 vector<int> res; 15 bitset<32> bit; 16 backtrack(res, bit, n, 0); 17 return res; 18 } 19 };
解法二:一般迭代
本题规律如下:
- 从第0位到最高位,进行( | 1)或上1
- 每一位操作中,对既存的res,反向进行操作。
- (由于res中相邻的两个结果一定是只有一步操作差的,因此反向依次追加入res,也能保证相邻二者只有一步操作差)
- (至于为什么反向,为了保证:层与层之间的变换只有一步差<当前位追加 1 >)
- 每一位操作中,对既存的res,反向进行操作。
flip[0] res: [0000]->[0001]
{0000, 0001}
flip[1] res:对既存res从后往前:[0001]->[0011] [0000]->[0010]
{0000, 0001, 0011, 0010}
flip[2] res: 对既存res从后往前:[0010]->[0110] [0011]->[0111] [0001]->[0101] [0000]->[0100]
{0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100}
flip[3] res:对既存res从后往前:[0100]->[1100] [0101]->[1101] [0111]->[1111] [0110]->[1110] [0010]->[1010] [0011]->[1011] [0001]->[1001] [0000]->[1000]
{0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100, 1100, 1101, 1111, 1110, 1010, 1011, 1001, 1000}
代码参考:
1 class Solution { 2 public: 3 vector<int> grayCode(int n) { 4 vector<int> res = {0}; 5 for(int pos = 0; pos < n; pos++) { 6 int size = res.size(); 7 for(int flip = size-1; flip >=0; flip--) { 8 res.push_back(res[flip] | 1<<pos); 9 } 10 } 11 return res; 12 } 13 };