前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【每天一个小知识】为什么二分法不建议使用 (right + left) / 2?

【每天一个小知识】为什么二分法不建议使用 (right + left) / 2?

作者头像
lomtom
发布2021-10-27 15:22:39
1.3K0
发布2021-10-27 15:22:39
举报
文章被收录于专栏:博思奥园

每天一个小知识,不定期更新

一、问题

事情是这样的,由于我最近在刷题,刷到这样一道题:

代码语言:javascript
复制
你是产品经理,目前正在带领一个团队开发新的产品。
不幸的是,你的产品的最新版本没有通过质量检测。
由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。
实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。


示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。

调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true

所以,4 是第一个错误的版本。 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-bad-version

乍一看,题目是挺简单的。直接采用二分法就可以立马解决。于是我潇潇洒洒的写下

代码语言:javascript
复制
public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left  = 1, right = n;
        while(left < right){
            int mid = (right + left) / 2;
            if (isBadVersion(mid)){
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
}

也许,你看到我的代码,你会想没错啊!!!

自己也会这样写。是的在我之前所有的二分法都是这样写的。

当我满怀信心的点了提交,然而

代码语言:javascript
复制
运行失败:
Time Limit Exceeded
测试用例:2126753390
1702766719

?????????Why

二、分析

须知:Integer都有自己的表示范围,他有定义 MAX_VALUEMIN_VALUE

代码语言:javascript
复制
/**
 * A constant holding the minimum value an {@code int} can
 * have, -2<sup>31</sup>.
 */
@Native public static final int   MIN_VALUE = 0x80000000;

/**
 * A constant holding the maximum value an {@code int} can
 * have, 2<sup>31</sup>-1.
 */
@Native public static final int   MAX_VALUE = 0x7fffffff;

,当我们的数超过他所规定的最值时,Integer将无法表示。

因此在我们上述算法中,

  1. left <= MAX_VALUE和 right <= MAX_VALUE是肯定的
  2. 但是left+right <= MAX_INT 我们无法确定,所以会造成栈溢出。

那么知道问题所在,我们怎么修改我们的代码呢?

我们可以使用

代码语言:javascript
复制
int mid = left + (right - left) /2;

来代替

代码语言:javascript
复制
int mid = (right + left) / 2;

他们最后的结果都是一致的,却能够有效的避免栈溢出问题。

三、结论

所以在我们使用二分法时,我们可以使用 left+(right-left)/2来代替 (right+left)/2,来避免栈溢出。

参考: 1、为什么left +(right-left)/ 2不会溢出?:https://stackoverflow.com/questions/27167943/why-leftright-left-2-will-not-overflow 2、第一个错误的版本:https://leetcode-cn.com/problems/first-bad-version

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 博思奥园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、问题
  • 二、分析
  • 三、结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档