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 次 → ...
相关推荐
用户956256254294 分钟前
跟做:Firecrawl 单页转 Markdown 再丢进沙箱总结
python·api
愿有所息4 分钟前
记一次 ARM64 + JDK8 上 fastjson2 的诡异数据错乱
java
威哥爱编程23 分钟前
模拟面试智能体开发实战 02:回答等半分钟,谁还愿意练?把服务端和流式输出搭起来
python·agent·harmonyos
秋饼23 分钟前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
威哥爱编程32 分钟前
模拟面试智能体开发实战 01:面试挂了都不知道挂在哪?用 Python 给自己造一个随叫随到的 AI 面试官
python·agent·harmonyos
2601_967980111 小时前
Python行情API量化 02:顺序拉 20 要 2 秒?并发批量把时间压到 0.5 秒
python·api·限流·并发·量化
伞伞悦读1 小时前
【第81期】特征缩放怎么选:标准化、MinMax 与 Robust 的原理、泄漏对照和完整实验
人工智能·python·深度学习·机器学习
新*2 小时前
从一段 WebSocket 代码聊开:bytes 不是 zlib、binaryType 决定一切,15MB 大消息的零拷贝优化
javascript·python·websocket·性能优化·blob·zlib·arraybuffer
SL_staff2 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
SL_staff2 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc