【leet-code清晰解题思路💯✅】29. 两数相除

102 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

题目描述

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例 1:

输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3

示例 2:

输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2

提示:

  • 被除数和除数均为 32 位有符号整数。
  • 除数不为 0。
  • 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31,  2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。

解题思路

  • 最直接的想法是直接除法运算,可是题目要求不能直接用除法
  • 换一种思路,除法的商就是可以执行多少次减法。我们可以不断减除数并计数,但是考虑一下极端情况intmax/1时,运算复杂度为10^9,会超时,那怎么办呢?
  • 如果做过快速幂这种倍增思想的题目,我们可以用类似的想法。一次减一个太慢了,我们可以一次减2个、4个、8个...这相当于每一次运算出一个二进制位,logn次即可完成。在解题中我们是由大到小枚举的,也就是先从比被除数小的最大2的指数次倍数开始。
  • 但是要注意越界情况,比如-2^31/-1
  • 除此之外,还应该注意符号问题,这里先把除数,被除数都转化为负数,最后结果再带上符号即可。
func divide2(dividend int, divisor int) int {
   if dividend == int(^int32(^uint32(0)>>1)) && divisor == -1 {
      return int(int32(^uint32(0) >> 1))
   }
   ans := 0
   f := 1
   if dividend > 0 {
      dividend = -dividend
      f = -f
   }
   if divisor > 0 {
      divisor = -divisor
      f = -f
   }
   k := 1
   for dividend/2 <= divisor {
      divisor += divisor
      k += k
   }
   for k > 0 {
      if dividend <= divisor {
         ans += k
         dividend -= divisor
      }
      k /= 2
      divisor /= 2
   }
   return ans * f
}

image.png