查看: 5135| 回复: 19
跳转到指定楼层
上一主题 下一主题
收起左侧

[二分/排序/搜索] 讨论一下如何写 binary Search (比如lower/uppper bound)

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
每次写lower/upper bound类似的代码, 都纠结于  (1)  l,r是写成 l<r or l <=r,

  (2) return l, or r ? or m ? or others ?

举个例子啊: lower bound, (find the index of the larget key which is less or equal to the given key)
```
int lower_bound(int[] arr, int l, int r, target) {
   int largestIndex = -1;
   while(l <=r) {
       int m = l + (r-l)/2;
       if (arr[m] == target) {
          largestIndex = Math.max(largestIndex, m);
          r = m - 1;
       } else if (arr[m] > target) {
          r = m - 1;
       } else {
          largestIndex = Math.max(largestIndex, m);
          l = m + 1;
       }
   }
   return largestIndex;
}
```
这个是我自己喜欢用的版本。。 但是感觉用了Math。max。。 感觉不够精简。。。

大家一半都怎么写这个代码呢?  
可否一起讨论一下怎么最好。。

评分

参与人数 2大米 +4 收起 理由
TracyInSummer + 1 赞一个
14417335 + 3

查看全部评分


上一篇:大家不要气馁,零基础转码刷题真的只需要三个月
下一篇:Leetcode刷题笔记 #11. Container With Most Water || 附解法的解释和证明
推荐
achromatic 2020-8-14 00:32:54 | 只看该作者
全局:
这个问题下面的第一个回答特别好,二分查找有几种写法?它们的区别是什么? https://www.zhihu.com/question/36132386
从为什么左闭右开 和 while loop的循环不变量 - loop invariants的角度的分析了为什么这样写。

评分

参与人数 2大米 +2 收起 理由
yun332119 + 1 很有用的信息!
yottafear + 1 很有用的信息!

查看全部评分

回复

使用道具 举报

推荐
cjspower 2020-8-17 13:00:15 | 只看该作者
全局:
本帖最后由 cjspower 于 2020-8-17 13:01 编辑

我一般都用同一个模板,左闭右开
while (l < r) {
    m = l + (r - l) / 2
    if (f(m)) {
        r = m
    } else {
        l = m + 1
    }
}
这样可以求出令 f(l) == true 的l 的最小值,如果l == r则不存在

在leetcode里这个方法几乎可以ac所有的二分题.p.s. 如果觉得有用的话求米
回复

使用道具 举报

全局:
其实你可以理解一下什么叫lower bound。lowerbound其实指的是满足某种条件的下界。
二分查找可以理解成找到一个边界,左边符合某个条件,右边符合另一个条件。
lower bound指的就是右边的最左端点。
  1. while (left < right) {
  2.     int mid = (left + right) / 2;
  3.     if (arr[mid] < target) {
  4.         left = mid + 1;
  5.     } else {
  6.         right = mid;
  7.     }
  8. }
  9. return left;
复制代码

这段代码求的其实是arr[j] >= target的最小下标。也就是lower bound。
为什么left要等于mid加一呢,因为mid不满足这个条件,所以mid不会成为最终的分界点。
right确实是可以成为分界点的。

回复

使用道具 举报

全局:
网上有不同人总结的不同模版。你找其中一种你同意的风格,然后彻底理解,把它做成自己的模版,然后就再也不怕binary search了。别自己总结,因为你会漏掉很多情况的,相信我。(或者你自己总结后对比不同人别人总结的,你就明白你漏掉什么了)
回复

使用道具 举报

全局:
你可以去搜一下九章的二分模版,退出的时候再做一次判断
回复

使用道具 举报

🔗
ranbaoranbao 2020-8-13 13:07:44 | 只看该作者
回复

使用道具 举报

🔗
yanjinbin 2020-8-13 18:49:09 | 只看该作者
全局:
搜 c++ lower_bound函数  或者看下花花酱的 别自己总结了  既然你现在都还在搞清楚二分模版
回复

使用道具 举报

🔗
牛牛牛ALLU 2020-8-13 19:17:59 | 只看该作者
全局:
我自己也是对binary search有很多疑问。有时候if statement的顺序也有影响。还有时候l = mid + 1 还是l = mid分不清(我知道这个概念,但是有时候明明是l = mid + 1更准确,但是用l = mid可以得到更精简的代码)
回复

使用道具 举报

🔗
 楼主| SHALLWEFZUW 2020-8-13 19:48:56 | 只看该作者
全局:
ranbaoranbao 发表于 2020-8-13 13:07
https://leetcode-cn.com/circle/article/LXYqmM/

这个总结非常不错!尤其是loop之后对left,right指针的分析。。
回复

使用道具 举报

🔗
情报君 2020-8-14 00:50:28 | 只看该作者
全局:
你可以参考下python bisect库的实现, 我觉得挺不错的


def bisect_right(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    a[i-1]<=x<a[i]
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if a[mid] <= x: lo = mid+1
        else: hi = mid
    return lo

def bisect_left(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e < x, and all e in
    a[i:] have e >= x.  So if x already appears in the list, a.insert(x) will
    insert just before the leftmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.

    a[i-1]<x<=a[i]
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        if a[mid] < x: lo = mid+1
        else: hi = mid
    return lo

评分

参与人数 2大米 +2 收起 理由
Gapyeartosahara + 1 给你点个赞!
sanmao0715 + 1 赞一个

查看全部评分

回复

使用道具 举报

全局:
马克儿zszszszs
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表