【算法】剑指 Offer 专项突击版 Day1整数部分
题目地址:https://leetcode-cn.com/study-plan/lcof/?progress=wgzvtig
目标:要点总结,分享思路
I 【简单】001. 整数除法
难度:不算特别简单的基础题,主要考察二进制移位
要点:
- 思路为将除法替换为绝对值减法,但仅考虑暴力逐减会超时,考点为后续优化
- 边界判断,需要保证被减数、减数和结果在运算中处理不会超过最值
- 重点:在被减数 - 减数的逐次相减中可以优化为
被减数 - 减数的倍数(用左移N位代替)
举例:22 ➗ 3 = 7,过程为
22 - 3 = 19>3 ans = 1
19 - 3 = 14>3 ans = 2
…
移位优化为
22 - 3左移0位 = 19>3 ans = 1
22 - 3左移1位 = 22 - 6 = 16>3 ans = 1*2
22 - 3左移2位 = 22 - 12 =10>3 ans = 1*2*2 = 4
22 - 3左移3位 = 22 - 24 =-2<3 此时不再移位,改为考虑上一步的10 ➗ 3,同样的过程不再阐述
class Solution:
def divide(self, a: int, b: int) -> int:
INT_MIN, INT_MAX = -2**31, 2**31 - 1
ans = 0
# 以下操作防止a或b转正数溢出
if a == INT_MIN:
if b == -1: return INT_MAX # a取绝对值正溢除,故边界判断
if b == 1: return INT_MIN # a取绝对值正溢除,故边界判断
if b == a: return 1 # 同理
# 否则,a先减去一个b,防止a转正数溢出
a -= -abs(b)
ans += 1
if b == INT_MIN: # b为INT_MIN,结果必为0
return 0
flag = 0 if (a>0) ^ (b>0) else 1 # 异或判断符号 同号为1异号为0
a, b = abs(a), abs(b) # 均转为正数
# 这段循环移位是要点
for i in range(31, -1, -1): # 二进制右移,从最大位开始尝试
if a>>i >= b: # (a/2^i) >= b,即 a >= b*2^i,这里不直接对 b 操作,防止溢出
ans += 1<<i # ans += 2^i
a -= b<<i
return ans if flag else -ans
总结:减法代替除法的过程中,可优化为
被减数 - 减数的倍数,其中倍数用左移考虑
II 【简单】002. 二进制加法
难度:简单
要点:
- 模拟法解决二进制加法,从后往前加并记录进位
class Solution:
def addBinary(self, a: str, b: str) -> str:
res = ""
carry = 0 # 进位
i,j = len(a)-1,len(b)-1 # 二进制位数,从后往前相加
while i>=0 or j>=0 or carry !=0:
if i>=0:
a_vi,i = int(a[i]),i-1
else: a_vi = 0
if j>=0:
b_vj,j = int(b[j]),j-1
else: b_vj = 0
now = a_vi+b_vj+carry # 当前加法结果
if now>=2:
res += str(now-2)
carry = 1
else:
res += str(now)
carry = 0
return res[::-1] # 因从后往前的加,故颠倒
III【简单】003. 前 n 个数字二进制中 1 的个数
难度:简单,但考察角度很好
要点:
- 将每个数字转为二进制,暴力遍历可以实现,但时间复杂度太高。故优化为动态规划
- 动态规划方程为 奇偶之间的关系,如果是奇数比它小1的偶数多一个1,如果是偶数和它右移移位的1个数相同。可参见下述代码中注释部分
class Solution:
def countBits(self, n: int) -> List[int]:
# 动态规划
# 如果是奇数,如5 = 101,则它比偶数4 = 100多1个1
# 如果是偶数,如4 = 100,则它和右移一位的2 = 10一样多
dp = [0 for _ in range(n+1)]
# for i in range(1,n+1):
# if i%2 != 0: # 奇数
# dp[i] = dp[i-1]+1
# else: # 偶数
# dp[i] = dp[i>>1]
for i in range(1,n+1):
dp[i] = dp[i-1]+1 if i%2!=0 else dp[i>>1]
return dp