连续看我文章的朋友就会发现,我写文章有一个特点,总是用经典的例题引出一个方法,在之后的文章中才会介绍这种方法的详细信息。这样做的好处是:避免了先接触干巴巴的概念导致很多朋友看的时候会有索然无味这种体验,由具体题目的分析过程来一步一步优化,最终引出方法这种形式,更能让这种方法变得顺理成章,也更能让读者体会到方法的巧妙之处。这种由兴趣激发的探索的欲望对彻底掌握一种方法其实是比较重要的。直接去接触一种方法有可能目的只是学会,但是产生兴趣而去探索一种方法的始末才能真正了解、掌握甚至读懂其真正的奥秘所在。
下面,我将会给大家详细的介绍二分法的信息。
二分法起源于数学中找函数零点的问题:
对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
如图所示,区间的端点为 A 点和 B 点,函数的图像在区间 AB 范围内是单调递增的,现在要找函数图像的零点 C 。由于这个图像比较特殊,区间 AB 的中点正好是 C 点,所以只需要第一次判断区间中心点就可以找到。假设 D 点是区间的中心,那么可以看出 区间 AD之间的函数值全部小于零,因此全部不满足条件,区间 DB中,函数连续且单调递增,左半边函数值小于零,右半边函数值大于零,那么在 DB 之间必然存在一个位置 使得函数值等于零。也就意味着以 D 点为分界,左半边 一定没有答案,右半边一定有答案。这样不断缩小区间,不断逼近,一定能让包含答案的区间长度足够小,比题目要求的精度还要小,这个时候,区间内的任意一个实数都可以作为答案。使用这种方法求函数零点的条件是:在区间范围内,函数图像连续且单调。
现在将这种二分的思想运用在程序设计中,也能产生神奇的效果。
之前在例题中,我使用二分法的情境是这样的:由于 循环要进行 1e18 量级的次数,会超时,因此我在寻求一种方法,能够减少循环执行的次数,这个时候题目隐含的条件是 天数和麻雀个数是在逐天增加,也就是题目所给的条件呈现出来的是线性的关系,在区间的中心位置取测试点,将区间一分为二,这时候必然能够肯定有一个区间里所有的数据均不满足条件,而另一区间存在数据能够达到条件。如此将区间不断等分,每次都能巧妙减少一半的数据量,只在符合条件的区间中查找,效率非常高。(没看过之前文章的朋友可能需要看过昨天的文章才能了解)
二分法的使用条件:
- 待查找的序列区间单调有序(单调递增或单调递减都可以)
- 待查找序列和题目的要求建立的函数关系单调有序
也就是说,在将区间一分为二后,答案只能出现在其中的一个区间,不能同时出现在两个区间内,这样的情形下才适合二分。如果不能保证这个条件,那就需要考虑别的方法。
二分法使用方法:
假设待查找序列和题目的要求之间的关系是单调递增的,先取区间的中心,判断该处函数值和题目标准值的大小关系,如果函数值偏小,那么应该在中心右侧的区间继续查找;如果函数值偏大 ,那么应该在中心左侧区间继续查找,直到找到对应的值或者区间缩小到左右端点之间不再包含其他数据结束。
二分的思想很重要,面对具体的情形需要做相应的变通。