LeetCode之颠倒二进制位

it2026-02-10  6

**题目:**颠倒给定的 32 位无符号整数的二进制位。 示例: 提示: java版: 解法1 取模求和

与反转十进制整数使用取模除十累加的方法类似,   十进制:ans = ans * 10 + n % 10; n = n / 10;   二进制:ans = ans * 2 + n % 2; n = n / 2;但是,仅仅使用这种写法,会有一些问题,比如都要考虑是否整型溢出,Java的整数溢出后的二进制数会表示成负数(补码形式),Java中负数除以2会向零取整;具体可以参考这篇博客还有这个视频中: -3 / 2 = -1 而 -3 >> 1 = -2然后还要考虑前导零,因为十进制是不考虑前面是否还有零的,比如100反转后就是1,不用写成001,而二进制要考虑前导零的问题。所以综上所述,要使用位运算来避免溢出问题,同时循环32次。因为一共只有32位,所以时间复杂度和空间复杂度都是O(1)。 public class Solution { // you need treat n as an unsigned value public int reverseBits(int n) { int res = 0; for (int i = 0; i < 32; i++) { res = (res << 1) + (n & 1); n >>= 1; } return res; } }

方法二:按位翻转

public class Solution { // you need treat n as an unsigned value public int reverseBits(int n) { int res = 0; for (int i = 0; i <= 31; i++) { // res += (n & (1 << i)) != 0 ? 1 << (31 - i) : 0; // res |= (n & (1 << i)) != 0 ? 1 << (31 - i) : 0; res ^= (n & (1 << i)) != 0 ? 1 << (31 - i) : 0; } return res; } }

python版: 方法:逐位颠倒 虽然这个问题并不难,但它常常是面试开始时的一个热身问题。重点是测试一个人对数据类型和位操作的基本知识。 在面试的时候逐位颠倒作为最直接的解决方案

class Solution: # @param n, an integer # @return an integer def reverseBits(self, n): ret, power = 0, 31 while n: ret += (n & 1) << power n = n >> 1 power -= 1 return ret

方法二:带记忆化的按字节颠倒(进阶优化) 有人可能会说,每字节(8 位的比特位)反转可能更有效。由于该题的输入是固定的 32 位整数,所以在本题中不一定是这样的。但是在处理长字节流时,它会变得更有效。

使用字节作为迭代单位的另一个隐含优点是,我们可以使用记忆化技术,可以缓存先前计算的值,以避免重新计算。

记忆化的后续问题是:如果该函数多次被调用,你该如何优化。

若要按自己为单位反转位,可以应用上述所示的算法。在这里,我们展示一种完全基于算术和位操作,不基于任何循环语句,如下所示:

def reverseByte(byte): return (byte * 0x0202020202 & 0x010884422010)%1023

这个算法为用 3 个操作反转一个字节中的位,在 Sean Eron Anderson 的在线电子书 Bit Twiddling Hacks 中可以看到更多的细节

class Solution: # @param n, an integer # @return an integer def reverseBits(self, n): ret, power = 0, 24 cache = dict() while n: ret += self.reverseByte(n & 0xff, cache) << power n = n >> 8 power -= 8 return ret def reverseByte(self, byte, cache): if byte not in cache: cache[byte] = (byte * 0x0202020202 & 0x010884422010) % 1023 return cache[byte]

方法三: 在方法 2 中,我们展示了一个关于如何在不使用循环语句的情况下反转字节中的位的示例。在面试过程中,你可能会被要求在不使用循环的情况下反转整个 32 位。在这里,我们提出了一种只使用位操作的解决方案。

这种思想可以看作是一种分治的策略,我们通过掩码将 32 位整数划分成具有较少位的块,然后通过将每个块反转,最后将每个块的结果合并得到最终结果。

在下图中,我们演示如何使用上述思想反转两个位。同样的,这个想法可以应用到比特块上 算法:

我们可以通过以下步骤实现该算法:

首先,我们将原来的 32 位分为 2 个 16 位的块。然后我们将 16 位块分成 2 个 8 位的块。然后我们继续将这些块分成更小的块,直到达到 1 位的块。在上述每个步骤中,我们将中间结果合并为一个整数,作为下一步的输入。 class Solution: # @param n, an integer # @return an integer def reverseBits(self, n): n = (n >> 16) | (n << 16) n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8) n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4) n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2) n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1) return n
最新回复(0)