Python手搓代码:位运算(&、|、^、~、>>、<<) 类型算法总结

位运算简介

位运算能够大幅加快计算。

python中进制转换:
在这里插入图片描述

  • 可以用 (x >> k) & 1 得到 x 二进制表示的第 k

题目列表

或运算的最小翻转次数

在这里插入图片描述
给你三个正整数 a、b 和 c。

你可以对 a 和 b 的二进制表示进行位翻转操作,返回能够使按位或运算
a OR b == c 成立的最小翻转次数。

「位翻转操作」是指将一个数的二进制表示任何单个位上的 1 变成 0 或者 0 变成 1 。

输入:a = 2, b = 6, c = 5
输出:3
解释:翻转后 a = 1 , b = 4 , c = 5 使得 a OR b == c

题目ID:1318

  • 解题思路:
    遍历每个位,在第k位时:
    情况一:c[k] 为 1 ,当a[k]、b[k]为0时,需要翻转1位
    情况二:c[k] 为 0,添加a[k]+b[k] 即可

  • 实现代码:

class Solution:
    def minFlips(self, a: int, b: int, c: int) -> int:
        a,b,c,ans = bin(a)[2:],bin(b)[2:],bin(c)[2:],0
        maxLen = max(len(a),len(b),len(c))
        a,b,c = a.zfill(maxLen),b.zfill(maxLen),c.zfill(maxLen)
        for i in range(maxLen):
            if c[i]=="1":
                ans+=(int(a[i]) + int(b[i]) == 0)
            else:
                ans+= int(a[i])+int(b[i])
        return ans
  • 细节:
    上述方法较好理解
    若使用下面方法判断每个位效率更高,缺点是需要遍历所有位(数范围内)
bit_a, bit_b, bit_c = (a >> i) & 1, (b >> i) & 1, (c >> i) & 1

交替位二进制数

题目ID:693

给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:
换句话说,就是二进制表示中相邻两位的数字永不相同。

  • 解题思路:

方法一:模拟法对每两位进行判断
方法二:数字右移与原数字异或得到全1,进而判断全1

  • 实现代码:

方法一:

class Solution:
    def hasAlternatingBits(self, n: int) -> bool:
        idx = 31
        while not (n>>idx & 1):idx-=1
        for k in range(idx,-1,-1):
            if (n>>k & 1) == (n>>k+1 & 1):return False
        return True

方法二:

class Solution:
    def hasAlternatingBits(self, n: int) -> bool:
        a = n ^ (n >> 1) #101 010 → 111
        return a & (a + 1) == 0 #0111 & 1000 → 0
  • 细节:
    方法二也可以转为暴力判断法
    对32位数字进行符合条件的构造
    即:
return n in {
            1, 2, 5, 10, 21, 42, 85, 170, 341, 682, 1365, 2730, 5461, 10922,
            21845, 43690, 87381, 174762, 349525, 699050, 1398101, 2796202, 5592405,
            11184810, 22369621, 44739242, 89478485, 178956970, 357913941, 715827882,
            1431655765
        }

二进制表示中质数个计算置位

题目ID:762

给你两个整数 left 和 right ,在闭区间 [left, right] 范围内,统计并返回 计算置位位数为质数 的整数个数。

计算置位位数 就是二进制表示中 1 的个数。

例如, 21 的二进制表示 10101 有 3 个计算置位。

1 <= left <= right <= 10^6
0 <= right - left <= 10^4

  • 解题思路:

对区间内的每个数字统计1的个数
判断是否是质数
<10^4中1的个数不大于20
提前准备好所有质数:
2,3,5,7,11,13,17,19
用二进制代码保存
10100010100010101100

  • 实现代码:
class Solution:
    def countPrimeSetBits(self, left: int, right: int) -> int:
        return sum(((1 << bin(x)[2:].count('1')) & int("10100010100010101100",2)) != 0 for x in range(left, right + 1))
  • 细节:
    统计1的个数:bin(x)[2:].count(‘1’)
    与运算快速判断一个数是否在一批数之中

排序数组中只出现一次的数字

题目ID:2426

给定一个只包含整数的有序数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。

  • 解题思路:

同样的的数异或结果为0
0和任何数异或都等于任何数
当然,有序数组使用二分法是最快的

  • 实现代码:
class Solution:
    def singleNonDuplicate(self, nums: List[int]) -> int:
        for i in range(len(nums)-1):nums[i+1]^=nums[i]
        return nums[-1]
  • 细节:
    异或满足结合律交换律
    a ^ (b ^ c) = (a ^ b) ^ c
    a ^ b = b ^ a
    因此无视数组顺序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赛文X

觉得不错就打赏下呗mua~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值