文章目录
前言
二分查找是一种比较简单且基础的查找算法,多用于排序数组的快速查找。但其实二分查找也有非排序数组的应用。
引例
Leetcode162 寻找峰值
本题是一道经典的二分查找算法题,要求找到一个比左右相邻值大的峰值。如果用暴力解法,则时间复杂度为O(n),不符合题目时间复杂度的要求。
那么我们应如何降低本题的时间复杂度呢,答案是使用二分查找。
我们先找的中间下标mid。然后再和右边相邻值比较。因为本题相邻两个值不相等,则如果nums[mid] < nums[mid + 1]
则mid的mid + 1的数值呈一个上升趋势,则一定有一个极大值在mid的右边,于是我们可以把left角标收缩到mid。
如果nums[mid] > nums[mid - 1]
同理在mid的左侧有一个极大值。否则nums[mid]本身就是一个极大值。
这种类似于二分差找收缩取值范围的思想能够有效降低本题的时间复杂度。
示例代码如下
int findPeakElement(vector<int>& nums){int left = -1, right = nums.size() - 1;//这里暂定right是要取的值while (left + 1 < right){int mid = left + (right - left) / 2;if (nums[mid] > nums[mid + 1])right = mid;//这里使right一定取一个较大值,且使这个较大值被排除区间之外else//nums[mid] < nums[mid + 1]//较大值要么在区间之内,要么在right上,这样right边能收敛到这个值上left = mid;}return right;}
当然本题也可以扩展到二维二分查找。
Leetcode1901寻找峰值2
示例代码
int indexOfMax(const vector<int>& vec){return max_element(vec.begin(), vec.end()) - vec.begin();}vector<int> findPeakGrid(const vector<vector<int>>& mat){int n = mat.size();int m = mat[0].size();int left = -1, right = n - 1;while (left + 1 < right){int mid = left + (right - left) / 2;int maxj = indexOfMax(mat[mid]);if (mat[mid][maxj] > mat[mid + 1][maxj])right = mid;elseleft = mid;}return { right, indexOfMax(mat[right]) };}