扩展算法3-二分法

在编程中,查找是很重要的一环。

比方说,有一个一百万位的、单调递增的数组,需要你找到某个值在第几位;

比方说,有一个不规则函数,要你求出一个零点的位置;

等等等。

在这个时候,你总不能把这一百万都查找一遍吧?

这个时候

二分就派上用场了。

那么二分是什么呢?

你可以和同学做一个游戏,我们来模拟一下最基础的二分:

让你的同学在1-1000中随便抽取一个数字,然后让你猜

你每猜一个数字,让他告诉你,答案比这个数字大还是小;

那么,如果你每次都猜中间的数字,最多十次就可以猜出来答案了。

为什么呢?

因为2^10=1024>1000,2进制的10位最多能存储到1024的值,而1000在这里面。

你看,本来我们需要搜索1000次,现在10次就够了,这极大的优化了程序的时间复杂度。

我们来尝试一下最简单的二分算法:

//以下为情景1
//这里有一个写好的数组num[100000];
//我们要在这个数组里面查找6666这个数字的位置
//然后输出
int i = 0;//声明迭代器
int up = 100000;//声明上界
int down = 0;//声明下界
while(num[i] != 6666)
{
	int mid = (up + down)/2; //声明一个变量,用来存储上下界的中值
	if(num[mid] > 6666)up = mid;//如果num[mid]大于我们要找的6666,说明我们要找的6666的下标在mid之前,更新上界使其变为mid
    else down = mid;//否则在6666之后,更新下界
}

cout << i;

OK。

我们再来说一声二分法的变形。

比方说,现在有一个一元一次函数,

y=kx+b。

首先,函数已经给你了,

double func(doube x){
	return k * x + b;
}

然后我们再告诉你一个答案区间:

-1000到1000

以及答案精度:保留五位小数

下面来尝试一下:

//以下为情景2
//虽然一次函数你可以很简单的求出来kx+b=0的解,但是如果是三次函数呢?
//这里只是让你尝试一下方法
//来求kx+b=0的解
int i = 0;//声明迭代器
int up = 1000;//声明上界
int down = -1000;//声明下界
while(up-down<=0.00001)//循环条件为精度
{
	int mid = (up + down)/2; //声明一个变量,用来存储上下界的中值
	if(fucn(mid) * fucn(up) <= 0)down = mid;//根据零点存在性定理,如果func(mid) * func(up) <= 0,就说明答案在mid和up中间,那就更新down
    else up = mid;//否则更新up
}

cout << mid;//现在其实输出up、down、mid都可以,精度都满足

其实二分法还有很多很多的变种。

它的使用条件很简单:

只要这个东西是单调的,且有上下界,就可以用二分法来解决。

以后可能我们做的很多算法题都可以利用二分来提高运行速度。

最近的文章

算法扩展2-高精度

高精度:首先,我们知道,在计算机中,是以2进制存储数字的。一个int型整数占四个字节,能表示的最大数字为2^31-1。那么,如果我要表示一个几百位、甚至上千位的数字,我需要多大的空间呢?以一千位数为例,一千位数字最小为10^1000。以2为底10^1000的对数等于1000被以2为底10的对数约等于…

继续阅读
更早的文章

扩展算法4-滑动窗口法

以欧拉计划第八题讲解滑动窗口法如果现在这里有1000个数字7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954…

继续阅读