目录
题目规则
每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num 返回我选出的数字。
题目分析
首先针对 int guess(int num) 进行一个解释,这个函数可以传入一个数值num,并返回一个关系码,如果关系码返回-1 则代表我们猜的数值较大,如果关系码返回0 则代表我们才的数值正确,如果关系码返回1 则代表我们才的数值较小。
接下来解析题意,大致意思是说,我们去根据guess函数返回的关系,猜出来正确数值,并将正确数值返回(也就是传入到guess函数之后,函数返回值为0的数值),回想人与人之间进行猜数字游戏。
在此次游戏中,我们所扮演的身份就是左边蓝色玩家,guess函数扮演的就是右边红色玩家,根据上面的图中可以看出,蓝色玩家只要一直不断的进行数值区间缩小,距离正确值也就越近,总有一个数值会猜测到,因此可以开始写出第一份代码。
题目作答
暴力解题
既然我们知道数值的范围,那么只需要将这个范围中的每一个数值都判断一次就肯定可以出结果啦
public class MAIN1 {
public static int guess(int num) {
// 假设正确数值是100
int ok = 100;
// 返回猜测数值与100之间的关系
return Integer.compare(ok, num);
}
public static int guessNumber(int n) {
for (int i = 0; i <= n; i++) {
if (guess(i) == 0) return i;
}
return -1;
}
public static void main(String[] args) {
// 测试结果 为100
System.out.println("我们猜出的正确数值为:" + guessNumber(120));
}
}
二分查找
但是人与人之间猜测数字,是将范围内的所有数值都猜测一遍吗?我想肯定不是的,既然这里也给出了关系,可以利用关系查找出正确的数值所在范围,不断的缩小查找区间。
思路:将区间的左右边界以变量的形式创建出来,然后在区间内选出中间的数值,作为一个基准值,与基准值进行关系比较,进而缩小范围。
- 如果guess(基准值) = 1 ,代表基准值较小,因此所有比基准数值小的数值都不需要考虑了,直接将区间的左边界设置为基准值。
- 如果guess(基准值) = -1,代表基准值较大,因此所有比基准数值大的数值都不需要考虑了,直接将区间的右边界设置为基准值。
- 如果guess(基准值) = 0 ,代表基准值就是我们需要找的数值,直接将基准值返回。
public class MAIN1 {
public static int guess(int num) {
// 假设正确数值是100
int ok = 100;
// 返回猜测数值与100之间的关系
return Integer.compare(ok, num);
}
public static int guessNumber(int n) {
int l = 0, r = n;
while (l < r) {
int mid = l + ((r - l) >> 1);
int status = guess(mid);
if (status == 1) l = mid;
else if (status == -1) r = mid;
else return mid;
}
return -1;
}
public static void main(String[] args) {
// 测试结果
System.out.println("我们猜出的正确数值为:" + guessNumber(120));
}
}