题目描述

✅ 374. 猜数字大小

image-20260929094916354

image-20260929094916469

题意分析

系统在 [1,n] 中固定选择一个目标,每次调用 guess(num) 只得到它与猜测值的大小关系,需要据此找出目标。

返回 -1 表示猜大了,目标小于 num;返回 1 表示猜小了,目标大于 num;返回 0 才表示命中。反馈方向必须以“目标相对当前猜测的位置”理解。

解法:二分猜数

核心思路

[!blue]

候选值本来就是连续有序整数,不需要逐个试探。用闭区间 [left,right] 保存尚未排除的候选,并始终保证目标在其中;查询中点能够一次确定目标位于哪一半。

若反馈为零,直接返回 mid。若为负,目标严格小于中点,mid 及其右侧都可以排除,令 right = mid-1;若为正,目标严格大于中点,令 left = mid+1。这里已经单独处理了命中情况,因此两个未命中分支都不需要保留中点。

每次更新既保留了真正目标,又严格缩小候选范围。题目保证目标存在,正确反馈不会把全部候选排空。当左右边界相等时,只剩下的这个整数必然是目标,可以直接返回,不必为它再调用一次接口。

每轮把 guess(mid) 的结果存下来再分支,避免同一次判断重复查询。中点使用 left + (right-left)/2,即使 n 接近 32 位整数上限,也不会因直接相加而溢出。

解题步骤

  1. 初始化 left = 1、right = n,两个端点都属于合法猜测范围。
  2. 当 left < right 时计算中点,调用一次 guess(mid) 并保存反馈。
  3. 命中就返回;否则按反馈排除中点及不含目标的那一侧。
  4. 循环结束后返回 left。当 n == 1 时,初始区间已经唯一,无需查询。

代码实现

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left = 1;
        int right = n;

        while (left < right) {
            int mid = left + (right - left) / 2;
            // 每轮只调用一次接口,保存反馈后再分支。
            int result = guess(mid);

            if (result == 0) {
                return mid;
            }

            // 负反馈表示目标更小,排除中点和右侧区间。
            if (result < 0) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        return left;
    }
}
func guessNumber(n int) int {
    left, right := 1, n
    for left < right {
        mid := left + (right-left)/2
        // 每轮只调用一次接口,保存反馈后再分支。
        result := guess(mid)
        if result == 0 {
            return mid
        }
        // 负反馈表示目标更小,排除中点和右侧区间。
        if result < 0 {
            right = mid - 1
        } else {
            left = mid + 1
        }
    }
    return left
}

复杂度分析

  • 时间复杂度:$O(\log(n+1))$,每轮排除约一半候选。
  • 空间复杂度:$O(1)$。

关键点总结

[!green]

  • 返回负数表示目标更小,需要缩小右边界。
  • 未命中时中点可以排除,使用 mid±1。
  • 每轮只调用一次接口并复用结果。

易错点总结

[!yellow]

  • 记反反馈方向:把目标所在半区排除。
  • 使用 left=mid 配合向下取整:两个候选时可能不再推进。
  • 右端初值为 n-1:漏掉目标恰好为 n 的情况。
  • 直接相加计算中点:大范围时可能溢出。

相似题目

题目 难度 关联与区别
278. 第一个错误的版本 简单 都通过外部判定接口二分,本题每次得到偏大或偏小,原题找真假分界点。
704. 二分查找 简单 比较结果由guess接口提供,更新左右边界的逻辑与有序数组二分相同。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/92640209
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!