力扣第八十九题-格雷编码

160 阅读3分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

前言

力扣第八十九题 格雷编码 如下所示:

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

  • 每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 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 有一位不同

一、思路

题目的意思还是比较容易理解的,我们要保证两个条件就可以了:

  • 相邻的整数对应的二进制恰好有一位不相同,例如(3 的二进制为 101,相邻的整数可以为 7 二进制为 1114 二进制为 100 )
  • 需要保证每个整数都只出现一次

这一题有两中解法,你可以使用递归或者数学规律来解决这一题。在这里我使用数学规律来实现,因为这个效率比较高。

我们可以将 n1 ~ 3 列举一下(二进制表示)

  • n=0 时,编码为 [0]
  • n=1 时,编码为 [0, 1]
  • n=2 时,编码为 [00, 01, 11, 10]
  • n=3 是,编码为 [000, 001, 011, 010, 110, 111, 101, 100]

如下图所示:

image.png

我们发现这个编码的结果除去最高位后,实在中间 2^(n-1) 的位置翻转的,即 ret[i]ret[2^n -i] 的后面 n-1 个字符是相等的。

那么我们就可以利用这个规律来直接生成这个结果数组。

  1. 我们知道结果集中第一个结果是 0
  2. 第二个结果为 ret[2] = 1+ret[0](一二两个元素构成镜像)
  3. 第三个结果为 ret[3] = 2 + ret[2](一二与三四构成镜像)
  4. 第四个结果为 ret[4] = 2 + ret[0](一二与三四构成镜像)
  5. 第五个结果为 ret[5] = 4 + ret[4](一二三四与五六七八构成镜像)
  6. ......

每一次填充完后半部分,记得讲最高位的值 head = 2 * head。这表示下一次循环继续填充后半部分

二、实现

实现代码

实现代码与思路中保持一致

    public List<Integer> grayCode(int n) {
        List<Integer> ret = new ArrayList<>();
        ret.add(0);
        int head = 1;
        for (int i = 0; i < n; i++) {
            for (int j = head - 1; j >= 0; j--)
                ret.add(head + ret.get(j));
            head = 2 *head;
        }
        return ret;
    }

测试代码

    public static void main(String[] args) {
        new Number89().grayCode(3);
    }

结果

image.png

三、总结

这一题还是非常有意思的,非常值得一做。如果你感兴趣的话,也可以使用递归代替上面的迭代,使得代码看起来更简洁。

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~