【算法】剑指 Offer 专项突击版 Day1整数部分

【算法】剑指 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿芒Aris

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值