题目如下:
猜数字游戏的规则如下:
每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况:
-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样 pick == num
思路:
由题意,我们可以使用二分查找的方式找到猜的数.
步骤:
- 初始化 l o = 1 , h i = n , m i d = ( n + 1 ) / 2 lo = 1, hi = n, mid = (n+1)/2 lo=1,hi=n,mid=(n+1)/2 ;
- 采用
w
h
i
l
e
while
while 循环,当
g
u
e
s
s
(
m
i
d
)
!
=
0
guess(mid) != 0
guess(mid)!=0 时,执行如下操作:
- m i d = l o / 2 + ( h i − l o ) / 2 mid = lo/2+(hi-lo)/2 mid=lo/2+(hi−lo)/2;
- 若 g u e s s ( m i d ) < 0 guess(mid)<0 guess(mid)<0, 说明要找的数位于 [ l o , m i d − 1 ] [lo,mid-1] [lo,mid−1], 令 h i = m i d − 1 hi = mid-1 hi=mid−1;
- 若 g u e s s ( m i d ) > 0 guess(mid)>0 guess(mid)>0, 说明要找的数位于 [ m i d + 1 , h i ] [mid+1,hi] [mid+1,hi], 令 l o = m i d + 1 lo = mid+1 lo=mid+1;
- w h i l e while while 循环结束后,返回 m i d mid mid 即可.
代码:
public class Solution extends GuessGame {
public int guessNumber(int n) {
int lo = 1, hi = n, mid = (n + 1)/2;
while(guess(mid) != 0){
mid = lo + (hi - lo)/2;
if(guess(mid) == 1) lo = mid + 1;
else hi = mid - 1;
}
return mid;
}
}
复杂度分析:
每进行一次循环就将区间长度缩短了一半,故时间复杂度为 O ( l o g n ) O(logn) O(logn).
可能出现的问题:
计算
m
i
d
mid
mid 时如果用
m
i
d
=
(
h
i
+
l
o
)
/
2
mid = (hi+lo)/2
mid=(hi+lo)/2 可能会导致溢出从而超时.(别问我怎么知道的)😢