常见的位运算符
1.两整数之和(easy)
题目:不使用运算符 + 和 - ,计算两整数 a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
思路:异或,可看作无进位的加法【输入十进制的话,^ 是将十进制转为二进制,在做异或得到的结果再转为十进制,二进制的话则直接异或输出。eg:1^ 3=2 ,0b01^ 0b11=2】;位与再左移,可以获取进位;
a + b 的问题拆分为 (a 和 b 的无进位结果) + (a 和 b 的进位结果)
tip:在 Python 中,整数不是 32 位的,一直循环左移并不会存在溢出的现象,这就需要我们手动对 Python 中的整数进行处理,手动模拟 32 位 int 整型。
具体做法是将整数对 0x100000000 取模,保证该数从 32 位开始到最高位都是 0。
def getSum(self, a: int, b: int) -> int:
MASK = 0x100000000 # 2^32
MAX_INT = 0x7FFFFFFF # 整型最大值
MIN_INT = MAX_INT + 1
while b != 0:
carry = (a & b) << 1 # 计算进位
a = (a ^ b) % MASK # 取余范围限制在 [0, 2^32-1] 范围内
b = carry % MASK
return a if a <= MAX_INT else ~((a % MIN_INT) ^ MAX_INT)
2.2的幂(easy)
题目:给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
思路:对于N为2的幂的数,都有 N&(N-1)=0
def isPowerOfTwo(self, n: int) -> bool:
if n<=0:
return False
return (n&(n-1))==0
3.位1的个数(easy)
题目:编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
思路:N&(N-1)会把最后一个 1 的位变成 0 ,以此来计算1的个数
def hammingWeight(self, n: int) -> int:
res=0
while n!=0:
res+=1
n= n&(n-1)
return res
4.只出现一次的数字(easy)
题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
思路:采用异或,任何数与0异或等于本身,两数相同异或为0
可满足交换律和结合律 a^b ^c=(a ^c) ^b
def singleNumber(self, nums: List[int]) -> int:
x = 0
for i in nums:
x=x^i
return x
5.只出现一次的数字 II(medium)
题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
思路:数学方法:3(a+b+c)-(a+a+a+b+b+b+c)=2c
def singleNumber(self, nums: List[int]) -> int:
res = sum( set(nums))
return int((res*3-sum(nums))/2)
6.二进制求和(easy)
题目:给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “1”
输出: “100”
思路:与上面题求两数和思路一致,将二进制转十进制,再用异或求和,位与加左移获得进位,最终返回的是二进制
class Solution:
def addBinary(self, a, b) -> str:
x, y = int(a, 2), int(b, 2)
while y: #进位不为 0
answer = x ^ y #计算当前 x和 y 的无进位相加结果
carry = (x & y) << 1 #计算当前 x和 y的进位:
x, y = answer, carry
return bin(x)[2:]`在这里插入代码片`
7.数组中两个数的最大异或值 (medium)
题目:给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在O(n)的时间解决这个问题吗?
示例:
输入: [3, 10, 5, 25, 2, 8]
输出: 28
解释: 最大的结果是 5 ^ 25 = 28.
思路:时间限制在O(n),用暴力法两次循环肯定会超时。求两个数的最大异或值则即为找到最大的异或值,先找到最高位为1 的数,通过贪心算法的思想【就是尽可能地让最高位为1】,从左到右找到与这个最高位数异或为1 的数,不断筛选得到最终的结果
还有个公式: a ^ b = c , c ^ b = a
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
res = 0
mask = 0
for i in range(30, -1, -1):
mask |= (1 << i)
s = set() # 当前得到的所有前缀都放在哈希表中
for num in nums:
s.add(mask & num)
temp = res | (1 << i) # 贪心算法思想,若全部前缀遍历完都不符合条件,这个数位上就是0,否则为1
for prefix in s:
if temp ^ prefix in s:
res = temp
break
return res