二分查找的边界情况

一、手写二分的几种边界情况

1.普通查找值,找到即返回,不考虑位置

    //1.普通二分:查找数存不存在或者随便找一个
    public static int binarySearchOne(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            if( a[m]<target ){
                l=m+1;
            }else if( a[m]>target ){
                r=m-1;
            }else
                return m;
        }
        return -1;
    }

 

2.找第一个等于target的数

    //2.第一个等于target的数
    public static int firstEqual(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            //如果此时m是第一个等于target的数,r=m-1后不会再变了,等到l>r时就是第一个符合要求的元素
            if(a[m]>=target)
                r=m-1;
            else
                l=m+1;
        }
        //元素也可能不存在,需要先判断越界和符合情况
        if(l<n && a[l]==target)
            return l;
        return -1;
    }

 

3.找第一个大于target的数

    // 3.找第一个大于target的数
    public static int binarySearchFirstMore(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            if( a[m]>target )
                r=m-1;
            else
                l=m+1;
        }
        return l>=n?-1:l;
    }

 

4.找第一个大于等于目标值的数

    // 4.找第一个大于等于目标值的数
    public static int binarySearchFirstMoreEquals(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            if( a[m]>=target )
                r=m-1;
            else
                l=m+1;
        }
        return l>=n?-1:l;
    }

 

5.找最后一个等于target的数

    // 5.找最后一个等于target的数
    public static int lastEqual(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            if(a[m]<=target)
                l=m+1;
            else 
                r=m-1;
        }   
        if(r>=0 && a[r]==target)
            return r;
        return -1;
    }

 

6.找最后一个小于target的数

    // 6.找最后一个小于target的数
    public static int binarySearchLastLess(int target){
        int l=0,r=n-1,m;
        while(l<=r){
            m=(l+r)/2;
            if( a[m]<target )
                l=m+1;
            else
                r=m-1;
        }
        //如果r<0的话也是-1,不用判断了
        //return r<0?-1:r;
        return r;
    }

 

7.找最后一个小于等于target的数

    // 7.找最后一个小于等于target的数
    public static int binarySearchLastLessEquals(int target){
        int l=0,r=n-1,m;
        while (l<=r){
            m=(l+r)/2;
            if( a[m]<=target )
                l=m+1;
            else
                r=m-1;
        }
        //如果r<0的话也是-1,不用判断了
        //return r<0?-1:r;
        return r;
    }

 

8.用l+(r-l)/2替代(l+r)/2防止溢出

9.总结

(1)第一个...的情况最后返回的都是l,主要通过判断r的移动来操作

  • 寻找第一个等于target的,判断条件是if(a[m]>=target) r=m-1;最后判断l合法性以及是否存在;
  • 寻找第一个大于等于target的,判断条件也是if(a[m]>=target) r=m-1;
  • 寻找第一个大于target的,判断条件是if(a[m]>=target) r=m-1;

(2)最后一个...的情况返回的都是r,主要通过判断l的移动来操作

  • 寻找最后一个等于target的,判断条件是if(a[m]<=target) l=m+1;最后判断r合法性以及是否存在;
  • 寻找最后一个小于等于target的,判断条件也是if(a[m]<=target) l=m+1;
  • 寻找最后一个小于target的,判断条件是if(a[m]<target) l=m+1;

二、集合容器中的二分操作

1.有序不重复集合TreeSet

  • boolean contains(Object o) 判断是否存在元素o
  • E ceiling(E e) 返回第一个大于或等于e的元素
  • E higher(E e) 返回第一个严格大于e的元素
  • E floor(E e) 返回最后一个小于或等于e的元素
  • E lower(E e) 返回最后一个严格小于e的元素

如果以上方法没有找到元素,则返回null

无序不重复集合HashSet没有后四个方法

遍历集合

for(E e:treeSet)

2.有序不重复映射TreeMap

  • boolean contains(Object key) 判断是否存在键key
  • K ceilingKey(K key) 返回第一个大于或等于key的键
  • K higherKey(K key) 返回第一个严格大于key的键
  • K floorKey(K key) 返回最后一个小于或等于key的键
  • K lowerKey(K key) 返回最后一个严格小于key的键

如果以上方法没有找到元素,则返回null

无序不重复映射HashMap没有后四个方法

遍历集合

for (Map.Entry entry : treeMap.entrySet()) {
      System.out.println(entry);
}

 

三、推荐例题

 

posted @ 2021-04-29 18:44  守林鸟  阅读(539)  评论(0编辑  收藏  举报