題目描述:系統預先選定一個 1 到 n 之間的數字,你需要猜出這個數字。每次呼叫 guess(num) API,它會回傳:-1(你猜的數太大)、1(你猜的數太小)或 0(猜中了)。請實作函數找出這個數字。
解題思路:這是二元搜尋的直接應用。維護搜尋範圍 [lo, hi],每次取中間值 mid = lo + (hi - lo) / 2(避免溢位),呼叫 guess(mid)。若回傳 0 表示找到答案;若回傳 -1 表示答案比 mid 小,縮小到 [lo, mid-1];若回傳 1 表示答案比 mid 大,縮小到 [mid+1, hi]。每次迭代排除一半的搜尋空間,最終必定找到答案。
時間複雜度:O(log n) — 每次迭代將搜尋範圍減半,最多需要 log₂(n) 次猜測即可確定答案。
空間複雜度:O(1) — 只使用固定數量的整數變數(lo、hi、mid),無額外資料結構。
1. Set lo = 1, hi = n 2. While lo <= hi: a. Compute mid = lo + (hi - lo) / 2 b. Call result = guess(mid) c. If result == 0: return mid (answer found) d. If result == -1: set hi = mid - 1 (mid is too high) e. If result == 1: set lo = mid + 1 (mid is too low) 3. Return -1 (unreachable if input is valid)
方法一:線性搜尋
從 1 到 n 逐一猜測,直到 guess(i) == 0。時間複雜度 O(n),空間複雜度 O(1)。最直觀但效率極差,當 n 很大時不可接受。
方法二:遞迴二元搜尋
將迭代版二元搜尋改寫為遞迴形式:solve(lo, hi) → 若 guess(mid) == 0 回傳 mid,否則遞迴呼叫 solve(lo, mid-1) 或 solve(mid+1, hi)。邏輯與迭代版完全相同,時間複雜度 O(log n),但空間複雜度為 O(log n)(遞迴呼叫棧深度)。迭代版更節省空間,是首選實作方式。
mid 時為什麼使用 lo + (hi - lo) / 2 而非 (lo + hi) / 2?在什麼條件下後者會產生問題?guess() API 的成本很高(例如每次需要網路請求),如何估算本解法在最壞情況下的 API 呼叫次數(以 n 的函數表示)?