LeetCode刷题-猜数字大小

前言说明

算法学习,日常刷题记录。

题目连接

猜数字大小

题目内容

猜数字游戏的规则如下:

每轮游戏,我都会从1到n随机选择一个数字,请你猜选出的是哪个数字。

如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。

你可以通过调用一个预先定义好的接口int guess(int num)来获取猜测结果,返回值一共有3种可能的情况(-1,1或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

提示:

1 <= n <= 2^31 - 1

1 <= pick <= n

分析过程

看题可以得知用二分法查找,取1-n的中间值,调用guess函数和pick比较。

如果guess结果大于0,那么pick > num,选出的数字大于猜测的数字,所以选出的数字在区间[mid + 1, right]中。

如果guess结果小于0,那么pick < num,选出的数字小于猜测的数字,所以选出的数字在区间[left, mid - 1]中。

注意:这里的guess函数是两数相反了,因为拿了pick作为比较基准,而不是传递进去num参数作为比较基准,所以和我们平时的认知是刚好相反的。

所以如下代码:

/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        // 定义左右指标,左指标初始为1,右指标初始为n
        int left = 1, right = n;

        // 计算中间指标
        int center = (left + right) / 2;

        // 计算猜测结果
        int result = guess(center);

        // 循环直至guess的结果为0
        while (result != 0) {
            if (result > 0) {
                // 若是大于0,那么pick > num,选出的数字大于猜测的数字,所以选出的数字在区间[mid + 1, right]中
                left = center + 1;
            } else {
                // 若是小于0,那么pick < num,选出的数字小于猜测的数字,所以选出的数字在区间[left, mid - 1]中
                right = center - 1;
            }

            // 计算中间指标
            center = (left + right) / 2;;

            // 计算猜测结果
            result = guess(center);
        }

        // 当猜测结果为0时,即为二分查找到的数字
        return center;
    }
}

但是提交后提示运行时间超时:

运行结果

是什么原因呢?我们可以看一下提示中n的范围:

1 <= n <= 2^31 - 1

其实这里如果输入2^31 - 1和1,一开始就已经整数溢出了,所以可以想象,还可能会出现2^31 - 1和一个二分查找时的中间指标相加再除以2,2^31 - 1已经是整数最大值了,若再加一个数,肯定就整数溢出了,导致二分查找时中间指标发生了跳跃变化,最终导致运行时间超时,我们计算中间指标如下:

// 计算中间指标
int center = (left + right) / 2;

错误的地方就在这里,这里可能会导致整数溢出,我们需要用其他方法来计算中间指标,可以改成如下:

// 计算中间指标,不用center = (left + right) / 2来计算,防止计算时溢出
int center = left + (right - left) / 2;

这样一来,就不会出现整数溢出了。

解答代码

所以需要考虑整数溢出的问题,解答代码如下:

/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        // 定义左右指标,左指标初始为1,右指标初始为n
        int left = 1, right = n;

        // 计算中间指标,不用center = (left + right) / 2来计算,防止计算时溢出
        int center = left + (right - left) / 2;

        // 计算猜测结果
        int result = guess(center);

        // 循环直至guess的结果为0
        while (result != 0) {
            if (result > 0) {
                // 若是大于0,那么pick > num,选出的数字大于猜测的数字,所以选出的数字在区间[mid + 1, right]中
                left = center + 1;
            } else {
                // 若是小于0,那么pick < num,选出的数字小于猜测的数字,所以选出的数字在区间[left, mid - 1]中
                right = center - 1;
            }

            // 计算中间指标,不用center = (left + right) / 2来计算,防止计算时溢出
            center = left + (right - left) / 2;

            // 计算猜测结果
            result = guess(center);
        }

        // 当猜测结果为0时,即为二分查找到的数字
        return center;
    }
}

提交结果

执行用时0ms,时间击败100.00%的用户,内存消耗35MB,空间击败84.51%的用户。

运行结果

原文链接

原文链接:猜数字大小

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值