二分查找的边界情况
一、手写二分的几种边界情况
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); }
三、推荐例题