力扣刷题记录&整理——(十八)Bit Manipulation


前言

整理力扣刷题思路。

  • 语言:python
  • 题库:来自neetcode: link

一、预备知识

1.位运算

位运算是一种在整数的二进制表示上操作单个位的运算。在大多数编程语言中,包括Python,有7种基本的位运算:与(AND)、或(OR)、异或(XOR)、取反(NOT)、左移(LSHIFT)、右移(RSHIFT)以及无符号右移(无符号 RSHIFT,不过这在Python中并不直接支持)。下面是每种位运算的特性和示例:

  1. 与(AND)

    • 特性:对位进行AND运算,当两个相应的二进位都为1时,结果位才为1,否则为0。
    • 示例:5 & 3(0101 & 0011 -> 0001, 结果为1)
  2. 或(OR)

    • 特性:对位进行OR运算,当两个相应的二进位都为0时,结果位才为0,否则为1。
    • 示例:5 | 3(0101 | 0011 -> 0111, 结果为7)
  3. 异或(XOR)

    • 特性:对位进行XOR运算,当两个相应的二进位相异时,结果位才为1。
    • 示例:5 ^ 3(0101 ^ 0011 -> 0110, 结果为6)
  4. 取反(NOT)

    • 特性:对位进行NOT运算,将1变成0,0变成1。
    • 示例:~5 (~0101 -> 1010, 在8位整数上结果为-6,因为位模式表示的是补码)
  5. 左移(LSHIFT)

    • 特性:将一个数的所有位都向左移动指定的位数,高位丢弃,低位补0。
    • 示例:5 << 1(0101 << 1 -> 1010, 结果为10)
  6. 右移(RSHIFT)

    • 特性:将一个数的所有位都向右移动指定的位数。对于无符号数,低位丢弃,高位补0;对于有符号数,低位丢弃,高位补符号位(这取决于语言和系统,称之为算数右移)。
    • 示例:5 >> 1(0101 >> 1 -> 0010, 结果为2)

注意,Python中的右移是算数右移。

Python不直接支持无符号右移,但这在一些其他语言如Java中是存在的,其特性为:

  1. 无符号右移(无符号 RSHIFT)(不适用于Python):
    • 特性:与标准的右移(有符号右移)不同,无论正负,高位都补0。
    • 示例:在支持无符号右移的语言中,-5 >>> 1结果会把符号位视为普通位一样右移,并且高位补0。

位运算在计算机编程中非常有用,尤其是在需要直接操作整数的二进制表示时。它们通常用于图形编程、加密算法、优化代码性能、内存管理等领域,以及许多需要低层操作的系统编程任务。


二、解题思路

1.位运算

136.single-number

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
link

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ans = 0
        for num in nums:
            ans ^= num
        return ans

268.missing-number

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
link

class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        ans = len(nums)
        #相同的数异或结果为0,最后的结果即为数组中未出现的数
        for i,n in enumerate(nums):
            ans ^= i^n
        return ans

跟上一题其实是一样的

191.number-of-1-bits

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中
设置位的个数(也被称为汉明重量)。
link

#解法1:
class Solution:
    def hammingWeight(self, n: int) -> int:
        cnt = 0
        while n:
            cnt += n&1
            n >>= 1
        return cnt

#解法2:        
class Solution:
    def hammingWeight(self, n: int) -> int:
        cnt = 0
        while n:
            cnt += 1
            n &= n-1
        return cnt

参考:link

338.counting-bits

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
link

class Solution:
    def countBits(self, n: int) -> List[int]:
        cnt = [0]*(n+1)
        for i in range(1,n+1):
            cnt[i] = cnt[i>>1] + (i&1)
        return cnt

190.reverse-bits

颠倒给定的 32 位无符号整数的二进制位。

提示:

请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数 -1073741825。
link

#解法1
class Solution:
    def reverseBits(self, n: int) -> int:
        res = ''
        for _ in range(32):
            #倒序加入二进制的每一位
            res += str(n&1)
            n >>= 1
        return int(res,2)

#解法2
class Solution:
    def reverseBits(self, n):
        n = (n >> 16) | (n << 16);
        #f:1111,c:1100,3:0011,a:1010,5:0101
        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

参考:link

371.sum-of-two-integers

给你两个整数 a 和 b ,不使用 运算符 + 和 - ​​​​​​​,计算并返回两整数之和。
link

class Solution:
    def getSum(self, a: int, b: int) -> int:
        a &= 0xffffffff
        b &= 0xffffffff
        while b:
            #按位加法,a保存对应位置为0、1的相加结果,也即1
            #b保存两者皆为1的相加结果,进位1
            a,b = a^b, (a&b) << 1 &0xffffffff
        return a if a<=0x7fffffff else ~(a^0xffffffff)

link

7.reverse-integer

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。
link

class Solution:
    def reverse(self, x: int) -> int:
        y,ans = abs(x),0
        check = 0x7fffffff if x>0 else 0x80000000

        while y:
            ans = ans*10 + y%10
            y //= 10
            if ans > check:
                return 0
        return ans if x>0 else -ans

link

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,关于力扣刷C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷中经常会用到。例如,左移运算符 &lt;&lt; 可以用来计算 2 的幂次方,右移运算符 &gt;&gt; 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷中,使用 string 可以方便地处理字符串相关的问。 9. 注意边界条件:在力扣刷中,边界条件往往是解决问的关键。需要仔细分析目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值