来玩二分查找[NO.2]--左侧(右侧)边界的二分搜索

什么是左侧(右侧)边界二分查找

上一篇博客,细诉了二分查找的细节和实现逻辑,当时存在局限性,比如有一个数组int[] arr={1,2,2,2,3,5,7},目标num=2,返回索引是3,假如需要返回最左侧索引(1)或最右侧的索引(3),这样的话普通二分查找是无法实现的

来一个左侧边界二分查找:

public static int getTwoNum5(int[] arr, int num) {
		int left = 0;
		int right = arr.length;
		// while(left < right) 终止的条件是 left == right,此时搜索区间 [left, left)
		// 为空,所以可以正确终止
		while (left < right) {
			int index = (left + right) / 2;
			System.out.println("当前索引位置:" + index + "索引值为:" + arr[index]);
			if (num == arr[index]) {
				// 当查询索引index查询到标的值,不立即返回而是缩小right边界[left,index]继续往左侧边界查找
				right = index;
			} else if (arr[index] > num) {
				// 初始二分索引值比标的num值大,查询范围[0,index]
				right = index;
			} else if (arr[index] < num) {
				// 初始二分索引值比标的num小,查询范围[index+1,right)
				left = index + 1;
			}
		}
		return arr[left] == num ? left : -1;
	}

细节问题:

  • 为什么right=arr.length而不是arr.length-1
    答:因为搜索区间是左闭右开的,当arr[index]=num或者arr[index]>num时,循环范围都是[left,index),这样不断搜索区间靠左查询。

  • 为什么while的循环条件是<而不是<=
    答:当查询最左侧或者最右侧边界成立时即arr[index]=num,右侧边界会赋值为right=index,如果循环结束条件leth<=right,最左侧情况(0,0)或最右侧情况(arr.lenght-1,arr.lenght-1)出现死循环无法改出。

  • 为什么right=index;left=index+1
    答:是为了切割二分查询后左右两侧边界,当初次二分索引查询值比标的num大时,查询范围切割为[left,index),当比标的num小时,查询范围切割为[index+1,right)。

  • 为什么numarr[index]时right=index
    答:当查询索引index查询到标的值num时,不立即返回而是缩小right边界[left,index]继续往左侧边界查找,可以一直查到最左侧,如果出现[index+1,right],当num
    arr[index],则查询直接返回

  • 如果是右侧边界的二分搜索
    答:只需要在num==arr[index]成立时,不立即返回而是缩小left边界,赋值left=index+1继续向右侧查找[index+1,right].

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章