1. 首页

LeetCode 029. 两数相除

题目描述

给定两个整数,被除数 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 位有符号整数,其数值范围是 [−231,  231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。

难度:Middle

前置知识

  • 二分法

公司

  • 阿里
  • 腾讯
  • 百度
  • 字节

思路

符合直觉的做法是,减数一次一次减去被减数,不断更新差,直到差小于0,我们减了多少次,结果就是多少。

核心代码:

  let acc = divisor;
  let count = 0;

  while (dividend - acc >= 0) {
    acc += divisor;
    count++;
  }

  return count;

这种做法简单直观,但是性能却比较差. 下面来介绍一种性能更好的方法。

29.divide-two-integers

通过上面这样的分析,我们直到可以使用二分法来解决,性能有很大的提升。

关键点解析

  • 二分查找

  • 正负数的判断中,这样判断更简单。

const isNegative = dividend > 0 !== divisor > 0;

或者利用异或:

const isNegative = dividend ^ divisor < 0;

代码

  • 语言支持:JS,Python3


/* * @lc app=leetcode id=29 lang=javascript * * [29] Divide Two Integers */ /** * @param {number} dividend * @param {number} divisor * @return {number} */ var divide = function(dividend, divisor) { if (divisor === 1) return dividend; // 这种方法很巧妙,即符号相同则为正,不同则为负 const isNegative = dividend > 0 !== divisor > 0; const MAX_INTERGER = Math.pow(2, 31); const res = helper(Math.abs(dividend), Math.abs(divisor)); // overflow if (res > MAX_INTERGER - 1 || res < -1 * MAX_INTERGER) { return MAX_INTERGER - 1; } return isNegative ? -1 * res : res; }; function helper(dividend, divisor) { // 二分法 if (dividend <= 0) return 0; if (dividend < divisor) return 0; if (divisor === 1) return dividend; let acc = 2 * divisor; let count = 1; while (dividend - acc > 0) { acc += acc; count += count; } // 直接使用位移运算,比如acc >> 1会有问题 const last = dividend - Math.floor(acc / 2); return count + helper(last, divisor); }

Python3 Code:

class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        """
        二分法
        :param int divisor
        :param int dividend
        :return int
        """
        # 错误处理
        if divisor == 0:
            raise ZeroDivisionError
        if abs(divisor) == 1:
            result = dividend if 1 == divisor else -dividend
            return min(2**31-1, max(-2**31, result))

        # 确定结果的符号
        sign = ((dividend >= 0) == (divisor >= 0))

        result = 0
        # abs也可以直接写在while条件中,不过可能会多计算几次
        _divisor = abs(divisor)
        _dividend = abs(dividend)

        while _divisor <= _dividend:
            r, _dividend = self._multi_divide(_divisor, _dividend)
            result += r

        result = result if sign else -result

        # 注意返回值不能超过32位有符号数的表示范围
        return min(2**31-1, max(-2**31, result))

    def _multi_divide(self, divisor, dividend):
        """
        翻倍除法,如果可以被除,则下一步除数翻倍,直至除数大于被除数,
        返回商加总的结果与被除数的剩余值;
        这里就不做异常处理了;
        :param int divisor
        :param int dividend
        :return tuple result, left_dividend
        """
        result = 0
        times_count = 1
        while divisor <= dividend:
            dividend -= divisor
            result += times_count
            times_count += times_count
            divisor += divisor
        return result, dividend

复杂度分析
– 时间复杂度:$O(logN)$
– 空间复杂度:$O(1)$

相关题目

更多题解可以访问我的 码农周刊 仓库:https://github.com/meibin08/free-programming-books, 一起学习更多前端前沿知识。

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:LeetCode 029. 两数相除

链接:https://www.javascriptc.com/4389.html

« LeetCode 030. 串联所有单词的子串
精选10款谷歌浏览器插件武装你的浏览器»
Flutter 中文教程资源

相关推荐

QR code