关于LeetCode中Guess Number Higher or Lower一题的理解

题目如下:

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I'll tell you whether the number is higher or lower.

You call a pre-defined API guess(int num) which returns 3 possible results (-1,1, or0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!

Example:

n = 10, I pick 6.

Return 6.
    题目当然还是一如既往地好理解,就是一个猜数字的游戏。你猜一个数字,内置的guess(int num)函数告诉你要猜的数字比你猜的数字的值低了还是高了。例如:目标数字是6,guess(10)会返回-1,因为6<10。如果正好猜对了就返回0。我们要写的程序就是要把这个目标数字猜出来,过程就是通过不断调整n的大小,然后使用guess(n)函数来判断是大了还是小了,通过不断的尝试最后得到正确的值。最容易想到的方法是如果guess(n)返回-1我就让n=n-1,如果guess(n)等于1我就让n=n+1,这样最后肯定能得到正确的结果。确实能得到正确的结果,但是你还会得到一个大大的“超时”提示。说明这种最容易想到的方法是行不通的,那我们就很容易想到一种需要运行次数更好的方法,二分法。确定一个比目标值大的右边界,再确定一个比目标值小的左边界,不断取中间值进行比较,然后确定新边界,最终一定会找到和目标值相等的n。思路就是这样,已Accepted的代码如下所示,上面有我加的一些注释方便理解:(题干中的目标值是从1到n中选择的,所以并不会出现目标值比n大的情况,我这种方法包含了目标值比n大的情况,这里其实还有一些小隐患,n*2是有可能超出int类型最大值的,所以在赋值之前要弄一个long类型的进行判断,要是n*2大于int类型最大值,就令n赋值为int类型最大值,若不大于正常进行赋值即可)

public int guessNumber(int n) {
        int left = 0;
        int right = 0;
        int flag = 0;
        while(true){
            flag = guess(n);
            if(flag == -1){ // target number < n
                right = n;
                n = left+(right-left)/2;
            }else if(flag == 1){ // target number > n
                if(right>0){ //if right boundary has existed
                    left = n;
                    n = left+(right-left)/2;
                }else{      //if right boundary has not existed, double 'n' to make it bigger than guessnumber
                    n = n*2;
                }
            }else{
                return n;
            }
        }
    }

   稍微修改了一下,这样n*2就不会溢出了,代码如下所示:

    public int guessNumber(int n) {
        int left = 0;
        int right = 0;
        int flag = 0;
        while(true){
            flag = guess(n);
            if(flag == -1){ // target number < n
                right = n;
                n = left+(right-left)/2;
            }else if(flag == 1){ // target number > n
                if(right>0){ //if right boundary has existed
                    left = n;
                    n = left+(right-left)/2;
                }else{      //if right boundary has not existed, double 'n' to make it bigger than guessnumber
                    long test = n;
                    test = test*2;
                    if(test > 2147483647L){
                        n = 2147483647;
                    }else{
                        n = n*2;
                    }
                }
            }else{
                return n;
            }
        }
    }

   这道题是有Editoral Solution的,我们现在就来看一下,Editoral Solution中的其他解法。

    第一种方法就和我提到的方法类似,他的方法是从1开始遍历,最终总能遇见目标值,显然这种方法会超时,代码如下所示:

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        for (int i = 1; i < n; i++)
            if (guess(i) == 0)
                return i;
        return n;
    }
}
    第二种方法也是利用了二分搜索,和我的方法类似,这里就直接放代码了:

 public int guessNumber(int n) {
        int low = 1;
        int high = n;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int res = guess(mid);
            if (res == 0)
                return mid;
            else if (res < 0)
                high = mid - 1;
            else
                low = mid + 1;
        }
        return -1;
    }
    第三种方法是使用三分搜索,解释的话大致直接看英文原文的解释好了,链接在这里:https://leetcode.com/articles/guess-number-higher-or-lower/ 。代码如下所示:

    public int guessNumber(int n) {
        int low = 1;
        int high = n;
        while (low <= high) {
            int mid1 = low + (high - low) / 3;
            int mid2 = high - (high - low) / 3;
            int res1 = guess(mid1);
            int res2 = guess(mid2);
            if (res1 == 0)
                return mid1;
            if (res2 == 0)
                return mid2;
            else if (res1 < 0)
                high = mid1 - 1;
            else if (res2 > 0)
                low = mid2 + 1;
            else {
                low = mid1 + 1;
                high = mid2 - 1;
            }
        }
        return -1;
    }

    大致就是这几种方法了,三分的时间复杂度比二分小,这个可以用主定理解释,主定理可以计算分治问题的时间复杂度,详细可以看这里:http://blog.chinaunix.net/uid-25267728-id-3802135.html 主要看那张图片就行,那个就是从算法导论上截出来的~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值