LeetCode 190.颠倒二进制位

LeetCode 190.颠倒二进制位

方法一:逐位颠倒

思路

将 n 视作一个长为 32 的二进制串,从低位往高位枚举 n 的每一位,将其倒序添加到翻转结果 rev 中。

代码实现中,每枚举一位就将 n 右移一位,这样当前 n 的最低位就是我们要枚举的比特位。当 n 为 0 时即可结束循环。

需要注意的是,在某些语言(如 Java)中,没有无符号整数类型,因此对 n 的右移操作应使用逻辑右移。

代码
cpp 复制代码
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t rev = 0;                     // 初始化一个变量 rev,用于存储反转后的结果,初始值为0
        for (int i = 0; i < 32 && n > 0; ++i) { // 循环32次,但若 n 变为0则可提前退出(优化)
            rev |= (n & 1) << (31 - i);       // 取出 n 的最低位,将它左移到对应的反转位置,然后通过按位或合并到 rev 中
            n >>= 1;                           // 将 n 右移一位,丢弃已处理的最低位,准备处理下一位
        }
        return rev;                            // 返回反转后的结果
    }
};
代码2
cpp 复制代码
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t ans = 0;          // 初始化结果变量 ans 为 0,用于逐步存储反转后的值
        int i = 32;                 // 设置循环计数器 i 为 32,表示要处理 32 位
        while(i--)                  // 循环 32 次,每次 i 减 1,直到 i 变为 0(后置递减,先判断 i 是否为非零,再减)
        {
            ans <<= 1;              // 将 ans 左移 1 位,为即将加入的新位腾出最低位的位置
            ans += n & 1;           // 取出 n 的最低位(n & 1),加到 ans 的最低位(此时 ans 最低位为 0,等效于设置该位)
            n >>= 1;                // 将 n 右移 1 位,丢弃已处理的最低位,使下一低位成为新的最低位
        }
        return ans;                 // 返回反转后的结果
    }
};

方法二:位运算分治

位运算分治(也称为并行位反转或分治位交换)是一种利用位运算掩码和移位操作,通过将数据划分为更小的块并并行交换相邻块的位置,从而高效地完成位序反转、位计数等任务的技术。其核心思想是分而治之:先将问题分解为若干独立的小规模子问题(如交换相邻的1位),然后逐层扩大交换的规模(2位、4位、8位等),最终得到整体结果。整个过程不需要循环,时间复杂度为 O(log n) 次操作(对于32位整数只需5步),且所有操作都是按位并行执行,效率极高。

以下代码运用了这种分治原理来实现32位无符号整数的二进制位反转:

cpp 复制代码
class Solution {
private:
    const uint32_t M1 = 0x55555555; // 0101... 用于交换相邻1位
    const uint32_t M2 = 0x33333333; // 0011... 用于交换相邻2位
    const uint32_t M4 = 0x0f0f0f0f; // 00001111... 用于交换相邻4位
    const uint32_t M8 = 0x00ff00ff; // 0000000011111111... 用于交换相邻8位

public:
    uint32_t reverseBits(uint32_t n) {
        // 第1步:交换相邻的1位(即每2位为一组,将组内高低位互换)
        n = n >> 1 & M1 | (n & M1) << 1;
        // 第2步:交换相邻的2位(即每4位为一组,将前后两个2位互换)
        n = n >> 2 & M2 | (n & M2) << 2;
        // 第3步:交换相邻的4位(即每8位为一组,将前后两个4位互换)
        n = n >> 4 & M4 | (n & M4) << 4;
        // 第4步:交换相邻的8位(即每16位为一组,将前后两个8位互换)
        n = n >> 8 & M8 | (n & M8) << 8;
        // 第5步:交换高16位和低16位
        return n >> 16 | n << 16;
    }
};
原理详解

掩码的作用:每个掩码的二进制模式是交替的"0"和"1"块,用于提取偶数位置或奇数位置的位组。例如 M1 = 0x55555555 的二进制为 0101...,它保留了所有偶数位(第0、2、4...位),而将奇数位清零。

每一步的操作

(n & M1) << 1:提取偶数位并左移1位,使它们移到奇数位的位置。

n >> 1 & M1:将原数右移1位,提取原来的奇数位(现在位于偶数位),然后与M1相与得到这些位。

两者按位或,即完成相邻位的交换。

后续步骤类似,只是掩码和移动的位数逐步加倍。经过五次交换,最终实现了整个32位数的完全反转。

这种分治算法利用了位运算的并行性,无需循环,执行速度极快,是处理位反转问题的经典优化方法。

相关推荐
ʚ希希ɞ ྀ4 小时前
岛屿数量 -- 图论
算法·深度优先·图论
兰令水4 小时前
leecodecode【反前后指针】【2026.5.31打卡-java版本】
java·开发语言
aWty_5 小时前
实分析入门(11)--Cantor三分集
学习·数学·算法·实变函数
兰令水5 小时前
leecodecode【二叉树递归+对称】【2026.6.1打卡-java版本】
算法
AI人工智能+电脑小能手11 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
来杯@Java12 小时前
图书管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·mybatis·课程设计
地平线开发者13 小时前
profiler debug 工具用法与高一致性策略
算法·自动驾驶
卷毛的技术笔记13 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
编程大师哥13 小时前
匿名函数 lambda + 高阶函数
java·python·算法
東雪木13 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试