LeetCode之颠倒二进制位

**题目:**颠倒给定的 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值