算法每日一练(2022年1月8日)格雷编码

2022年1月8日

格雷编码

🌔题目描述

n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:

  • 每个整数都在范围 [0, 2n - 1] 内(含 02n - 1
  • 第一个整数是 0
  • 一个整数在序列中出现 不超过一次
  • 每对 相邻 整数的二进制表示 恰好一位不同 ,且
  • 第一个最后一个 整数的二进制表示 恰好一位不同

给你一个整数 n ,返回任一有效的 n 位格雷码序列

示例 1:

输入:n = 2
输出:[0,1,3,2]
解释:
[0,1,3,2] 的二进制表示是 [00,01,11,10] 。
- 00 和 01 有一位不同
- 01 和 11 有一位不同
- 11 和 10 有一位不同
- 10 和 00 有一位不同
[0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。
- 00 和 10 有一位不同
- 10 和 11 有一位不同
- 11 和 01 有一位不同
- 01 和 00 有一位不同

示例 2:

输入:n = 1
输出:[0,1]

提示:

  • 1 <= n <= 16

🎯题解

公式

本题我采用公式法进行解答,具体的推理过程我是看的力扣的题解的视频讲解。

如果我们有一个二进制数序列,我们也可以将它直接转换成格雷码序列。假设 n 位二进制数为 b,对应的格雷码为 g,转换规则如下:

g(i) = b(i+1) ⊕ b(i), 0≤i<n

其中 ⊕ 是按位异或运算,g(i) 和 b(i) 分别表示 g 和 b 的第 i 位,且 b(n)=0。

具体的就是用二进制数推出格雷码序列

  • 0 1 2 3
  • 00 01 10 11 二进制数
  • 00 00 01 01 右移一位
  • 00 01 11 10 按位异或^
  • 0 1 3 2
代码实现
//公式实现
package everyday_answer_day2;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * 	当n=1时 [0,1]
 * 	00 01
 *	 0  1
 *	当n=2时 [0,3]
 *	 0  1  2  3
 *	00 01 10 11
 *	00 00 01 01 右移一位
 *	00 01 11 10	按位异或^
 *	00 01 11 10
 *	 0  1  3  2
 *	当n=3时 [0,7]
 *	000 001 011 010 110 111 101 100
 *    0   1   3   2   6   7   5   4
 * 	
 */

public class Solution {
	public List<Integer> grayCode(int n) {
	    List<Integer> target=new ArrayList<Integer>();
	    for (int i = 0; i <= 1<<n; i++) {//要生成2的n次方个格雷码
	    	target.add(i^i>>1);//生成格雷码的公式i^i>>1
		}
	    return target;
	    }
}



规律
假设我们得到第n位的格雷码创建第n+1位的格雷码的规律如下
n位格雷码的集合位{a,b,c,d}
我们将该集合的每一个元素复制一次逆序排序
同时每次在元素后面增加1或者0就得到n+1位的格雷码的集合
a0
b0
c0
d0
d1
c1
b1
a1
以已知2位的格雷码为00 01 11 10为例
就可以得到3位的格雷码
000
010
110
100
101
111
011
001
代码实现
//规律实现
public class Solution {
	public List<Integer> grayCode(int n) {
	    List<Integer> ans=new ArrayList<Integer>();
	    ans.add(0);//0位的格雷码位0
	    while (n--!=0) {
	    	List<Integer> tmp=new ArrayList<Integer>(); 
	    	for (int i = 0; i < ans.size(); i++) {
				tmp.add(ans.get(i)<<1);//前半部分在后面加个0
			}
	    	for (int j=ans.size()-1; j >=0; j--) {
				tmp.add((ans.get(j)<<1)+1);//后半部分翻转在加上1
			}
	    	ans=tmp;
		}
	    
	    return ans;
	    }
}
复杂度分析
  • 时间复杂度:O(2^n),其中 n为格雷码序列的位数。每个整数转换为格雷码的时间复杂度为 O(1),总共有 2^n个转换。
  • 空间复杂度:O(1)。注意返回值不计入空间复杂度。

🐄我的看法

今天的题目是关于二进制的题目,本人对二进的位运算符并不是很了解,所以看了一下位运算符的运算规则,整理在了文章末尾。

除了公式法之外,本题还可以用规律法进行解答,今天在这里我没有进一步的去深究规律(并不是太想去思考)

加油,每天进步一点点!🎃

⛵️ 补充知识

位运算符

Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。

位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:

A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011

下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:

操作符描述例子
如果相对应位都是1,则结果为1,否则为0(A&B),得到12,即0000 1100
|如果相对应位都是 0,则结果为 0,否则为 1(A | B)得到61,即 0011 1101
^如果相对应位值相同,则结果为0,否则为1(A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。(〜A)得到-61,即1100 0011
<<按位左移运算符。左操作数按位左移右操作数指定的位数。A << 2得到240,即 1111 0000
>>按位右移运算符。左操作数按位右移右操作数指定的位数。A >> 2得到15即 1111
>>>按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。A>>>2得到15即0000 1111
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值