LeetCode 374 使用循环代替递归的二分查找从而避免栈溢出的错误

题意是这样的:


大致的意思就是会给出一个n,然后在[1, n]中间挑一个数,题目会给一个方法guess(int num)来帮助判断你猜的数是否正确,如果你猜的数和题目挑的数一样,返回0,如果题目挑的数更小,返回-1,如果题目挑的数更大,返回1。

一开始拿到题目感觉这就是一个二分查找,所以就用二分查找的方法做了,用了递归

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        return myGuessNumber(1, n);
    }
    
    private int myGuessNumber(int begin, int end) {
        if (begin == end) {
            return begin;
        }
        int middle = (begin + end) / 2;
        int result = guess(middle);
        if (result == 0) {
            return middle;
        } else if (result < 0) {
            return myGuessNumber(begin, middle - 1);
        } else {
            return myGuessNumber(middle + 1, end);
        }
    }
}
测试了一下没有问题,就提交了,结果报了栈溢出



这下就比较尴尬了,还想着是不是要换方法,但是数据量这么大的话,还是要用二分查找会比较快,要不然可能会超时。想了半天,原来二分查找还可以用循环来实现

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        return myGuessNumberLoop(1, n);
    }
    
    private int myGuessNumberLoop(int begin, int end) {
        while (begin < end) {
            int middle = (begin + end) / 2;
            int result = guess(middle);
            if (result == 0) {
                return middle;
            }
            if (result < 0) {
                end = middle - 1;
            } else {
                begin = middle + 1;
            }
        }
        return begin;
    }
}
提交后报了另外一个错误,超时


感觉已经没招了,只能去网上搜资源了,这时候看到另外一种写法,尝试了一下,其实只是修改了一行

int middle = (begin + end) / 2;
替换为

int middle = begin + (end - begin) / 2;
然后就过了。。。

只能根据答案猜原因了,这句话是放在循环中执行的,当数据比较大的时候,begin + end 可能会溢出,也有可能是比较大的数的除法比比较小的数的除法要耗时,所以导致上面一种写法会超时但是下面的写法就不会超时。

看了一下网站给出的答案,网站一共给出了三种做法,第一种是直接遍历,肯定超时。第二种是循环的二分查找,第三种是循环的三分查找,这里贴一下代码

public class Solution extends GuessGame {
    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;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值