二分搜索的巧妙应用

来源:互联网 发布:网络端口怎么设置 编辑:程序博客网 时间:2024/05/29 09:22

今天同事问我一道算法题,题目是这样:

给定一个递增循环整数数组,从里面找出最小的元素,使用的算法越快越好。特别地,最小的元素可能出现在数组中间。比如:50, 52, 63, 90, 3, 8, 15, 44。

解析:

这里有条件:1、递增。2、循环

对于有序的数组,二分搜索一般是解决此类问题的利器,可以将时间复杂度从O(n)提高至O(log(n))。可这里却有一个较为苛刻的条件,是循环递增。

二分搜索的核心思想:利用现有的条件,每一次的搜索,都可以将目标的范围缩小一半,从而实现加速查找的效率。我们不用死守着最基本那一套。

这里把可能的趋势图画一下:

1、最低------------------最高(这里最特殊的一种情况)


这里情况最好办了,直接判断最后一个是否大于第一个元素的值即可判断。

2、大低----------大高,最低----------小高(这是最普遍的情况)


因为是循环递增,所以以最小值为界,左半边的值,全部都大于右半边。二分搜索的关键在于,不停在向目标点(最小值靠近)

算法:

初始化left=array[0], right = array[len-1];

每次取中点值mid = (left + right) / 2;

while (left  + 1 < right )  //这里考虑到只有两个值情况下,那就返回array[right],或者本身right所在位置就是最小值,不停搜索之后,直接返回array[right]即是答案

{

如果array[mid ] 比它前面一个值要小,那说明它便是最小值了,算法退出,返回最小值。

如果arrary[mid] < arrary[right],那说明取得的mid位置落到了右半边,将右边界移到mid,继续下次二分搜索。

如果array[mid ] > arrary[left], 说明mid位置落到了左半边,那将左边界移到mid,继续下次二分搜索。

}

return array[right];


退出循环后,那right便是已经逼到了最小值位置了。


3、当最小值在最右边的时候。



得出算法出下所示:

int findmin( int array[], int count ){//情况1if (array[count - 1] > array[0]){return array[0];}int left = 0, right = count - 1;//情况2while(right > left + 1){int mid = (left + right) / 2;if(array[mid] - array[(mid-1+count)%count] < 0 ) return array[mid];else {if(array[mid] - array[left] > 0) left = mid;else right = mid;}}//情况3时return array[right];}


                                             
0 0
原创粉丝点击