题目描述

✅ 397. 整数替换

image-20260928224004614

image-20260928224004619

题意分析

从正整数 n 出发,偶数只能除以 2,奇数可以加 1 或减 1,每次操作计一步,求到达 1 的最少步数。难点是奇数的方向选择:暂时变大,也可能换来更多次除以 2。

解法:贪心 + 位运算

核心思路

[!blue]

偶数没有选择,直接右移一位。奇数加减 1 后都会变成偶数,下一步都必须除以 2,因此可以比较这两步之后的剩余状态,选择后续代价不更大的方向。

记 f(x) 为从 x 到 1 的最少步数,f(1) = 0、f(2) = 1。由操作规则,f(2k) = 1 + f(k),而 f(2k + 1) = 2 + min(f(k), f(k + 1)),后式适用于大于 1 的奇数。

这两个式子还说明:大于 1 的奇数,其最少步数不小于相邻两个偶数。可以从 f(1)、f(2) 归纳:若 f(k) 与 f(k + 1) 相差至多 1,代入两式后,f(2k + 1) 与 f(2k)、f(2k + 2) 的差都只可能为 0 或 1。于是相邻状态的差仍至多 1,并得到上述奇偶比较结论。

对 x = 4k + 1,减一再除二到 2k,加一再除二到 2k + 1,前者是偶数,因此选减一不劣。对 x = 4k + 3 且 x > 3,两条路分别到 2k + 1 和 2k + 2,所以选加一不劣。对应二进制规则就是:低两位为 01 时减一,为 11 时加一,优先创造可继续右移的末尾 0。

唯一要单独处理的是 3:减一再除二就已到终点 1,只需两步;加一后还要经过 4、2、1,需要三步。输入为 1 时则无需操作。

解题步骤

  1. 把输入转为 long 或 int64,令操作次数为 0。
  2. 只要当前值大于 1,偶数就右移一位。
  3. 奇数等于 3,或低两位满足 (x & 3) == 1 时减一;其余奇数加一。
  4. 每轮累加一次操作,达到 1 时返回次数。

最大输入为 2^31 - 1,选择加一会产生 2^31,所以必须先提升类型再运算。虽然加一步会暂时增大数值,但随后必定除以 2,常数次操作后规模就会缩小。

代码实现

// 奇数时,若 n == 3 或 n % 4 == 1,选择 n - 1。
class Solution {
    public int integerReplacement(int n) {
        // 先转宽整数,承载最大输入加一的中间值
        long x = n;
        int steps = 0;

        while (x > 1) {
            if ((x & 1) == 0) {
                x >>= 1;
            } else {
                // 低两位决定调整方向,三减一可直接更快到达终点
                if (x == 3 || (x & 3) == 1) {
                    x--;
                } else {
                    x++;
                }
            }

            steps++;
        }

        return steps;
    }
}
// 奇数时,若 n == 3 或 n % 4 == 1,选择 n - 1。
func integerReplacement(n int) int {
    // 先转宽整数,承载最大输入加一的中间值
    x := int64(n)
    steps := 0

    for x > 1 {
        if x&1 == 0 {
            x >>= 1
        } else {
            // 低两位决定调整方向,三减一可直接更快到达终点
            if x == 3 || x&3 == 1 {
                x--
            } else {
                x++
            }
        }
        steps++
    }

    return steps
}

复杂度分析

  • 时间复杂度:$O(\log(n+1))$,调整后可以右移,常数次操作使数值规模缩小。
  • 空间复杂度:$O(1)$,当前值与计数。

关键点总结

[!green]

  • 贪心选择不必唯一,目标是最少步数而非唯一操作序列。
  • 两条奇数分支先各花两步,再用剩余状态的最优步数比较,不是只比较加减后的大小。
  • 3 的例外来自减一分支直接到达终点,不能套用一般奇偶比较。

易错点总结

[!yellow]

  • 用窄整数承载最大值加一,会回绕成负数。
  • 忽略三的例外,会多走一步。
  • 奇数一律减一,会错过进位消除末尾连续 1 后,多次直接除以 2 的机会。

相似题目

题目 难度 关联与区别
991. 坏了的计算器 中等 同样可通过反向观察操作减少分支,本题偶数除2、奇数加减1,原题倍增与减1的方向不同。
1342. 将数字变成 0 的操作次数 简单 原题奇数只能减1,本题还能加1,因此需要比较后续能连续除2的机会。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2025/99030167
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!