手撕二分查找(Binary Search),什么循环小于等于,到底加不加1,统统手撕给你看

本篇文章适合大致了解“二分查找”到的朋友看,如果不知道二分查找是什么,不适合看此篇文章。

我尽量以通俗易懂的话来说明白二分查找,目的是让大家明白,而不是把它封装成神秘的样子。

虽然文字较多,但你静下心来,仔细看,我相信它会对你有所帮助。

在这里以

· 定义区间范围

· while的循环条件到底如何确定

· 左右区间如何缩小(何时加1,何时不加)

这三个问题展开

1、明确区间定义

二分最开始、最基础的,就是要先【明确区间定义

什么意思呢?就是说:你想搜索的区间,到底是左闭右闭 [left,right] ,还是左闭右开 [left,right) ,还是左开右开(left,right),还是.......经常用到的是左闭右闭左闭右开,下面我会以这两个来举例。
(解释以下左闭右闭是什么:闭 就是包含,开就是不包含。左闭,就是包含left,右闭就是包含right。如果是左闭右开,就是包含left,不包含right)

把搜索区间明确好,就要牢记你的区间,不是记它是从哪个下标到哪个下标,而是记住 左闭 还是 左开,右闭 还是 右开

2、while 的循环条件到底如何确定?

判断left < right 或者 left <= right 是不是合法区间

还记得区间是如何定义的吗,举个例子:【明确区间定义】,我定义的是 [left,right],这个是左闭右闭。重头戏来了:

· 假如写成 while(left <= right),先甭管它是错是对,来判断一下,当 left == right,此时去看定义的区间,因为是 左闭右闭,是包含了 left 和 right 这两个边界的,所以它是一个合法的区间。故在我定义的区间 [left,right] 这个情况下,循环条件就是 while(left <= right)

· 假如写成 while(left < right),也先甭管它是错是对,来判断一下,当 left < right 时,会进入循环吧,但当 left == right 时,就不会进入循环吧,重点来了:我明明定义的是 [left,right],包含了两个边界的,也就是当这两个边界指向同一个下标时,就不会对指向的这个元素进行搜素。但我定义的 [left,right] 是包含了当 left == right 这种情况下,也要进行搜索的呀。所以说不能写成 left < right。

我怕大家还是没明白,再举个例子:这次区间定义成 [left,right),包含左边界,不包含右边界。

· 假如写成 while(left <= right),一样的,判断 left <= right 是不是合法区间。当 left == right 时,会进入循环吧,当 left == right,也就是左边界和右边界都是同一个下标,对于左边界来说是可以的,因为区间定义的时候,本来就包含了左边界。但对于右边边界来说,不包含右边界,那么又不能包含这个下标。左边界要包含这个下标,右边界又不要包含这个下标,是不是矛盾啦,它就不是个合法区间,所以不能写成 while(left <= right)

· 假如写成 while(left < right),那么 left == right,就不会进入循环,就不会出现上面说的“左边界要包含这个下标,右边界又不要包含这个下标”,所以它就是个合法区,写成 while(left < right)

3、左右区间如何缩小(何时加1,何时不加)

left = mid ? 还是  left = mid + 1 ?还是  right = mid ? 还是 right = mid - 1 ?

来看这个: if(target < nums[ mid ])接下来要干嘛?就缩小搜索搜索范围哈。带你分析一波:

因为 target < nums[ mid ],注意,nums[ mid ] 已经大于 target 了,就是说 nums[ mid ] 这个元素一定不是 target,mid 指向的这个元素一定不是要的结果。此时就又要回去最基础的那步了,【明确区间定义】,你定义的区间是什么?[left,right],[left,right),(left,right),还是.....?
假如是 [left,right]【此时是 while(left <= right)】,根据 if(target < nums[ mid ]),就要改变右边界,right = mid - 1,因为:mid 指向的元素绝对不是要的结果,区间定义有包含了右边界,所以 right = mid - 1。为什么不是 right = mid ?因为mid指向的元素绝对不是要的结果,区间定义又包含了右边界,把右边界又取到mid,本来下一次搜索区间不能再包含 mid 指向的元素的,又把它加进去,下一次搜索的范围就错了,这就是边界改变错的根源!会影响到最后的结果。

那如果区间定义是 [left,right)【此时是 while(left < right)】,if(target < nums[ mid ]),mid 指向的元素绝对不会是最后的结果,此时 right = mid。为什么不是 right = mid - 1?因为区间定义中,是不包含右边界的,把 right = mid,在下一次的搜索区间不会包含 mid 指向的元素,搜索区间就正确了嘛。

最后:

我不知道大家是否能够看懂,我已经尽力去解释了,如果第一遍没懂,就再多读几遍,它一定一定一定一定会对你有帮助!!!切记不要背这些代码,理解到了根本不需要背这个二分,随便写!

呈上举例的代码:(如果对  &  不知道怎么使用的,欢迎看我的另一篇文章,嘻嘻嘻)

int binary_Search(vector<int> &nums, int x)
{
    // 区间定义成 [left, right]
    int left = 0, right = nums.size() - 1;
    while (left <= right)            // 根据区间定义,所以 left <= right
    {
        int mid = (left + right) / 2;
        if (x < nums[mid])
            right = mid - 1;        // 根据区间定义,包含右边界
        else if (x > nums[mid])
            left = mid + 1;         // 根据区间定义,包含左边界
        else
            return mid;
    }
    return -1;
}
int binary_Search(vector<int> &nums, int x)
{
    // 区间定义成 [left, right)

    // 要对整个 nums[] 进行搜素,right 就是数组长度-1
    // 因为区间定义成 [left, right),不包含右边界,所以要是 right = nums.size()
    int left = 0, right = nums.size();
    while (left < right)     // 根据区间定义,所以 left < right
    {
        int mid = (left + right) / 2;
        if (x < nums[mid])
            right = mid;        // 根据区间定义,不包含右边界
        else if (x > nums[mid])
            left = mid + 1;         // 根据区间定义,包含左边界
        else
            return mid;
    }
    return -1;
}

最后的最后,写一篇文章真不容易呀,哈哈哈哈哈哈,如果对你有帮助,点个赞呗 ^_^,谢谢啦~~

如果有问题,放心大胆地指出来,我一定洗耳恭听~~~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值