二分查找总结

二分搜索?莫非就是对于一个值单调递增的序列,给出(l,r),将要找的值与区间([l,r])的中点值(a[m])比较,大了(l)变成(m),小了(r)变成(m)呗?但是如果不细究,很容易发生off one错误。下面我们将要讨论该问题。

序列内没有重复数字

int Bsearch(int l, int r, int key, int *a)
{
	while(l <= r)
	{
		int mid = (l + r) >> 1;
		if (a[mid] == key)
			return mid;
		if (key < a[mid])
			l = mid + 1;
		else
			r = mid - 1;
	}
	return -1;
}

因为没有重复数字,所以如果mid的值就是所求,返回mid就可以,否则既然mid的值无效了,范围缩小后的区间就不包括mid了。

LowerBound和UpperBound

int LowerBound(int l, int r, int key, int *a)
{
    if (key > a[r])
        return NO_ANS;
	while(l < r)
	{
		int mid = (l + r) >> 1;
		if (key <= a[mid])
			r = mid;
		else
			l = mid + 1;
	}
	return l;
}

int UpperBound(int l, int r, int key, int *a)
{
    if (key < a[l])
        return NO_ANS;
	while(l < r)
	{
		int mid = (l + r + 1) >> 1;
		if (key >= a[mid])
			l = mid;
		else
			r = mid - 1;
	}
	return l;
}

定义

LowerBound:给出(l,r,x),通过给出(p)的形式,求得一个区间([p,r]),使得任意一个下标(k),(kin [p,r]Leftrightarrow a_kgeq x)
UpperBound:给出(l,r,x),通过给出(p)的形式,求得一个区间([l,p]),使得任意一个下标(k),(kin [l,p]Leftrightarrow a_kleq x)
(m=frac{l+r}{2})
左区间:([l,lfloor m floor]),右区间:([lceil m ceil,r])
在LowerBound代码中,mid为(lfloor m floor);在UpperBound代码中,mid为(lceil m ceil)

原理

看看两个代码中mid的定义,发现无论是UpperBound,还是LowerBound,其缩小区间时,要么缩小到左区间,要么缩小到右区间。

序列中存在(a_k=x)

这意味着(k)的值可能有多个。

(r-l+1)为偶数

这意味着(m otin mathbb{Z})。如果(a_{lfloor m floor},a_{lceil m ceil})中存在不多于1个与(x)相等,这简单,若(xgeq a_{lceil m ceil}),则转移到右区间;若(xleq a_{lfloor m floor}),则转移到左区间。两个代码都满足这个要求。
如果(a_{lfloor m floor},a_{lceil m ceil})两个值都与(x)相等,则因为LowerBound要的(k)值最小,所以它要舍弃(a_{lceil m ceil}),在左区间中寻找(kleqlfloor m floor,a_k=x),故要求转移到左区间。同理UpperBound要求转移到右区间。

(r-l+1)为奇数

这意味着(minmathbb{Z})。若(a_m eq x),则若(x<a_m),则转移到左区间,否则转移到右区间;
(a_m=x),LowerBound要在左区间中寻找(kleqlfloor m floor,a_k=x),故要求转移到左区间。同理UpperBound要求转移到右区间。

序列中不存在(a_k=x)

一开始是普通的二分,最后会遇到这种情况:(m otinmathbb{Z})(a_{lfloor m floor}<x<a_{lceil m ceil})。如果是LowerBound,因为(x>a_{lfloor m floor}),LowerBound的定义要求所得区间内所有值都要大于(x),故要舍弃(a_{lfloor m floor}),故转移到右区间;UpperBound同理转移到了左区间。

我们看到mid的定义以及小于大于等于判断及其操作,都满足上述要求。

原文地址:https://www.cnblogs.com/headboy2002/p/8977085.html