Leecode#29刷题之两数相除

题目

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

整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8-2.7335将被截断至 -2

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

注意: 假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [−231, 231 − 1] 。本题中,如果商 严格大于 231 − 1 ,则返回 231 − 1 ;如果商 严格小于 -231 ,则返回 -231

示例 1:

复制代码
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = 3.33333.. ,向零截断后得到 3 。

示例 2:

复制代码
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。

提示:

  • -231 <= dividend, divisor <= 231 - 1
  • divisor != 0

Java语言

java 复制代码
class Solution {
    public int divide(int dividend, int divisor) {
        // 溢出处理:唯一会溢出的情况
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        // 记录符号,转为正数计算
        boolean negative = (dividend < 0) ^ (divisor < 0);
        long a = Math.abs((long) dividend);
        long d = Math.abs((long) divisor);

        int result = 0;

        // 倍增法:每次尽可能多地减
        while (a >= d) {
            long temp = d;
            long multiple = 1;
            while (a >= (temp << 1)) {
                temp <<= 1;
                multiple <<= 1;
            }
            a -= temp;
            result += multiple;
        }

        return negative ? -result : result;
    }
}

核心思路: 倍增法(快速减法)。不用一个一个减,而是每次把除数翻倍,减掉尽可能大的部分,大幅加速。


逐行说明:

java 复制代码
if (dividend == Integer.MIN_VALUE && divisor == -1) {

return Integer.MAX_VALUE;

}

唯一会溢出的情况:-2147483648 / -1 = 2147483648,超过 Integer.MAX_VALUE,按题目要求返回 MAX_VALUE

java 复制代码
boolean negative = (dividend < 0) ^ (divisor < 0);

用异或 ^ 判断结果是否为负:两个符号不同时为 true

java 复制代码
long a = Math.abs((long) dividend);

long d = Math.abs((long) divisor);

转成 long 再取绝对值,避免 Integer.MIN_VALUE 取绝对值溢出。

java 复制代码
int result = 0;

while (a >= d) {

long temp = d;

long multiple = 1;

while (a >= (temp << 1)) {

temp <<= 1;

multiple <<= 1;

}

a -= temp;

result += multiple;

}

核心倍增逻辑

  • temp:当前要减的值,从 d 开始
  • multiple:当前减的值对应多少个除数

每次把 temp 翻倍,直到再翻就超过 a 了。然后减掉这个最大的 temp,累加对应的 multiple

例如 10 / 3

复制代码
第 1 轮: temp=3, 翻倍=6 ≤ 10 ✓, 翻倍=12 > 10 停
  → 减掉 6, result += 2, a = 4
第 2 轮: temp=3, 翻倍=6 > 4 停
  → 减掉 3, result += 1, a = 1
a < 3, 结束

result = 2 + 1 = 3 ✓
java 复制代码
return negative ? -result : result;

根据符号返回结果。


示例 2 演示: dividend = 7, divisor = -3

复制代码
negative = true (7正, -3负, 符号不同)
a = 7, d = 3

第 1 轮: temp=3, 6≤7 ✓, 12>7 停 → 减6, result=2, a=1
a < 3, 结束

result = -2 ✓

时间复杂度 O(log n × log n),空间复杂度 O(1)。


python语言

python 复制代码
class Solution(object):
    def divide(self, dividend, divisor):
        # 溢出处理
        if dividend == -2**31 and divisor == -1:
            return 2**31 - 1

        # 记录符号,转为正数
        negative = (dividend < 0) ^ (divisor < 0)
        a = abs(dividend)
        d = abs(divisor)

        result = 0

        while a >= d:
            temp = d
            multiple = 1
            while a >= (temp << 1):
                temp <<= 1
                multiple <<= 1
            a -= temp
            result += multiple

        return -result if negative else result

Python 不需要 long 转换,因为 Python 整数不会溢出。abs() 直接用。^ 在 Python 中也是异或。<<= 左移赋值。逻辑完全一致。

倍增法适合线性增长太慢,需要指数级加速 的场景。核心思想是:不一步一步走,而是2 倍、4 倍、8 倍...地跳,快速缩小范围。

适合的场景

1. 代替逐次减法(本题)

复制代码
普通: 1000 - 3 - 3 - 3 - ... (333 次)
倍增: 1000 - 3 - 6 - 12 - 24 - 48 - 96 - 192 - 384 → 剩 235
      再来一轮: 235 - 3 - 6 - 12 - 24 - 48 - 96 - 192 → 剩 43
      ...大约 20 次搞定

2. 快速幂(计算 a^n)

复制代码
// 普通: a * a * a * ... 乘 n 次 → O(n)

// 倍增: a^16 = (a^8)^2 = ((a^4)^2)^2 = ... 只需 4 次 → O(log n)

2^10 = (2^5)^2 = (2^2 × 2^3)^2 = ...

直接算: 2×2×2×2×2×2×2×2×2×2 = 10 次

倍增法: 2^2 → 2^4 → 2^8 → 2^10,只需 4 次

3. 链表找中点 / 找环

复制代码
// 快慢指针本质就是倍增思想

// 慢指针走 1 步,快指针走 2 步

// 快指针到终点时,慢指针正好在中点

4. LCA(最近公共祖先)中向上跳

复制代码
// 普通做法:两个节点一步一步往上走 → O(n)

// 倍增法:预处理 2^k 步祖先,一次跳 2^k → O(log n)

5. RMQ / 区间最值

复制代码
// 预处理每个位置往后 2^k 的最值

// 查询时直接 O(1) 得到区间最值

共同特征

特征 一步一步 倍增法
步长 固定 1 1 → 2 → 4 → 8 → ...
时间 O(n) O(log n)
本质 线性 指数

判断口诀

当你发现一个问题需要反复做同一种操作 ,且可以成倍地跳时,就适合用倍增法:

复制代码
能减 3 → 能不能减 6 → 能不能减 12 → ...

能跳 1 步 → 能跳 2 步 → 能跳 4 步 → ...

能乘 1 次 → 能乘 2 次 → 能乘 4 次 → ...
相关推荐
smj2302_796826521 小时前
解决leetcode第4017题数组中的峰值II
python·算法·leetcode
午彦琳1 小时前
2026.9.9
数据结构·算法·leetcode
卷无止境1 小时前
AI Agent编程中,重构节奏与安全检查的门道
后端·python
luj_17681 小时前
中锋卡位与开放线博弈
c语言·开发语言·网络·经验分享·算法
慧都小妮子1 小时前
用 Python 批量把 PDF 参考文献排成 MLA 格式:Spire.Doc for Python 实战
python·pdf·c#·spire.doc·mla格式·参考文献排版·pdf批量处理
洋不写bug1 小时前
二叉树(四)经典算法题目解析,公共祖先,二叉树构造,非递归遍历
数据库·算法·二叉树·二叉树构造·公共祖先
卷无止境1 小时前
AI编程时代,代码复杂性正在悄悄失控
后端·python
开源量化GO1 小时前
看到“2026年 Python 与 API”时,用示例和拆解看清关系
人工智能·python
高洁012 小时前
大模型是怎么“学会“的:预训练、微调、对齐三段论
python·深度学习·transformer·知识图谱·tornado