力扣第89题 格雷编码

题目描述

格雷编码序列是一个二进制数字序列,其中的每两个相邻的数字只有一个二进制位不同。给定一个整数 n,表示格雷编码的位数,要求返回 n 位的格雷编码序列。

示例 1

输入

plaintext 复制代码
n = 2

输出

plaintext 复制代码
[0, 1, 3, 2]

解释

  • 对于 n = 2,对应的格雷编码序列为 [00, 01, 11, 10],它们的十进制表示为 [0, 1, 3, 2]

示例 2

输入

plaintext 复制代码
n = 3

输出

plaintext 复制代码
[0, 1, 3, 2, 6, 7, 5, 4]

解释

  • 对于 n = 3,对应的格雷编码序列为 [000, 001, 011, 010, 110, 111, 101, 100],它们的十进制表示为 [0, 1, 3, 2, 6, 7, 5, 4]

解题思路

格雷编码序列的生成有两种常见方法:

  1. 递归法
  2. 数学公式法

方法 1:递归法(构建反射法)

递归的核心思想是:

  1. 通过已有的 n n n 位的格雷编码序列,构建 n + 1 n+1 n+1 位的格雷编码序列。
  2. 假设已有 n n n 位的格雷编码序列为 G(n),我们可以通过以下方法得到 G(n+1)
    • G(n+1) 的前半部分是 G(n) 本身。
    • G(n+1) 的后半部分是 G(n) 的每个元素前面加上一个 1,并且反转原序列的顺序。

举个例子:

  • 对于 n = 1,格雷编码序列是 [0, 1]
  • 对于 n = 2,格雷编码序列是 [00, 01, 11, 10]

方法 2:数学公式法

格雷编码的数学公式为:
G ( k ) = k ⊕ ( k > > 1 ) G(k) = k \oplus (k >> 1) G(k)=k⊕(k>>1)

其中, k k k 是当前的数字, k > > 1 k >> 1 k>>1 是 k k k 右移一位, k ⊕ ( k > > 1 ) k \oplus (k >> 1) k⊕(k>>1) 是 k k k 与右移后的 k k k 进行按位异或操作。

使用该公式可以快速生成格雷编码序列。


代码实现

方法 1:递归法

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int* grayCode(int n, int* returnSize) {
    *returnSize = 1 << n;  // 返回的序列长度为 2^n
    int* result = (int*)malloc(sizeof(int) * (*returnSize));

    // 初始的 0 位格雷编码
    result[0] = 0;

    for (int i = 1; i <= n; i++) {
        int size = 1 << (i - 1);  // 当前格雷编码的长度
        for (int j = size - 1; j >= 0; j--) {
            result[size + j] = result[j] | (1 << (i - 1));  // 更新后半部分
        }
    }
    
    return result;
}

void printArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d", arr[i]);
        if (i < size - 1) printf(", ");
    }
    printf("\n");
}

int main() {
    int n = 3;
    int returnSize = 0;
    int* result = grayCode(n, &returnSize);
    printArray(result, returnSize);
    free(result);
    return 0;
}

方法 2:数学公式法

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int* grayCode(int n, int* returnSize) {
    *returnSize = 1 << n;  // 返回的序列长度为 2^n
    int* result = (int*)malloc(sizeof(int) * (*returnSize));

    for (int i = 0; i < *returnSize; i++) {
        result[i] = i ^ (i >> 1);  // 使用公式生成格雷编码
    }

    return result;
}

void printArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d", arr[i]);
        if (i < size - 1) printf(", ");
    }
    printf("\n");
}

int main() {
    int n = 3;
    int returnSize = 0;
    int* result = grayCode(n, &returnSize);
    printArray(result, returnSize);
    free(result);
    return 0;
}

代码详解

1. 递归法实现

  • 我们从最简单的格雷编码 [0] 开始,逐步扩展到 n n n 位。
  • 每次扩展时,通过反射法创建新的序列:
    • 将已有的序列复制到前半部分。
    • 将每个数值在前面加上 1,并将该部分的顺序反转,加入到后半部分。

2. 数学公式法实现

  • 通过公式 G ( k ) = k ⊕ ( k > > 1 ) G(k) = k \oplus (k >> 1) G(k)=k⊕(k>>1) 来计算每个数字的格雷编码。
  • 通过位运算,我们可以在 O ( 1 ) O(1) O(1) 的时间内生成每个数字的格雷编码。

时间与空间复杂度

时间复杂度

  • 对于递归法:生成每一位的格雷编码序列时,需要 O ( 2 n ) O(2^n) O(2n) 的时间,因此时间复杂度是 O ( 2 n ) O(2^n) O(2n)。
  • 对于数学公式法:直接计算每个数字的格雷编码,因此时间复杂度是 O ( 2 n ) O(2^n) O(2n)。

空间复杂度

  • 对于两种方法:需要存储生成的格雷编码序列,空间复杂度是 O ( 2 n ) O(2^n) O(2n)。

测试用例

示例 1:

输入

plaintext 复制代码
n = 2

输出

plaintext 复制代码
[0, 1, 3, 2]

示例 2:

输入

plaintext 复制代码
n = 3

输出

plaintext 复制代码
[0, 1, 3, 2, 6, 7, 5, 4]
相关推荐
浩哥学JavaAI3 小时前
2026年最新AI agent面试(10)_通信与行业动态
人工智能·面试·职场和发展
可编程芯片开发4 小时前
基于MATLAB的PEF湍流风场生成器模拟与仿真
算法
罗西的思考4 小时前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (9)--- Reward Judging
人工智能·算法·机器学习
Mr.HeBoYan6 小时前
一次持续三天才出现的丢包故障——深入解析 DPDK Memory Ordering、rte_ring 与 CPU Memory Barrier (下)
linux·网络·算法·架构·dpdk
wabs6666 小时前
关于图论【深度优先搜索的理论基础】
算法·深度优先·图论
先吃饱再说7 小时前
LeetCode 101. 对称二叉树
算法
是Dream呀8 小时前
人眼看不出的伪造,AI如何识别?实测合合信息跨模态鉴伪与去反光技术
算法
QN1幻化引擎8 小时前
SFA 信号场注意力:用8KB参数换248x KV Cache压缩,边缘设备也能跑长序列
人工智能·算法·gitee·gitlab
段一凡-华北理工大学8 小时前
向量数据库实战:选型、调优与落地~系列文章03:向量相似度算法全解:余弦、欧氏、内积,到底该用哪个?
大数据·数据库·人工智能·算法·机器学习·向量相似度·高炉炼铁
cjr_xyi9 小时前
AT1202Contest_c binarydigit 题解
c语言·c++·算法