Swift - LeetCode - 猜数字大小

713 阅读1分钟

我正在参加「掘金·启航计划」

题目

猜数字游戏的规则如下:

  • 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
  • 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。

你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-11 或 0):

  • -1:我选出的数字比你猜的数字小 pick < num
  • 1:我选出的数字比你猜的数字大 pick > num
  • 0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num 返回我选出的数字。

示例 1:

  • 输入: n = 10, pick = 6
  • 输出: 6

示例 2:

  • 输入: n = 1, pick = 1
  • 输出: 1

示例 3:

  • 输入: n = 2, pick = 1
  • 输出: 1

示例 4:

  • 输入: n = 2, pick = 2
  • 输出: 2

方法一:二分查找

思路及解法

记选出的数字为 pick\textit{pick},猜测的数字为 xx。根据题目描述,若 guess(x)0\texttt{guess}(x)\le 0 则说明 xpickx\ge\textit{pick},否则 x<pickx<\textit{pick}

根据这一性质我们可以使用二分查找来求出答案 pick\textit{pick}

二分时,记当前区间为 [left,right][\textit{left},\textit{right}],初始时 left=1\textit{left}=1right=n\textit{right}=n。记区间中间元素为 mid\textit{mid},若有 guess(mid)0\texttt{guess}(mid)\le 0 则说明 pick[left,mid]\textit{pick} \in [\textit{left},\textit{mid}],否则 pick[mid+1,right]\textit{pick} \in [\textit{mid}+1,\textit{right}]。当区间左右端点相同时,则说明我们找到了答案,退出循环。

代码

class Solution : GuessGame {
    func guessNumber(_ n: Int) -> Int {
        var left: Int = 1
        var right: Int = n
        while left < right {
            let mid = (right - left) / 2 + left
            if guess(mid) <= 0 {
                right = mid
            } else {
                left = mid + 1
            }
        }
        return left
    }
}

复杂度分析

  • 时间复杂度:O(logn)O(\log n)。时间复杂度即为二分的次数,每次二分我们将区间的长度减小一半,直至区间长度为 11 时二分终止,而区间初始长度为 nn,因此二分次数为O(logn) O(\log n)

  • 空间复杂度:O(1)O(1)