【算法日志】非排序数组的二分查找应用

文章目录


前言

二分查找是一种比较简单且基础的查找算法,多用于排序数组的快速查找。但其实二分查找也有非排序数组的应用。


引例

Leetcode162 寻找峰值

【算法日志】非排序数组的二分查找应用_第1张图片本题是一道经典的二分查找算法题,要求找到一个比左右相邻值大的峰值。如果用暴力解法,则时间复杂度为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& 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

【算法日志】非排序数组的二分查找应用_第2张图片

示例代码

	int indexOfMax(const vector& vec)
	{
		return max_element(vec.begin(), vec.end()) - vec.begin();
	}
	vector findPeakGrid(const vector>& 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;
			else
				left = mid;
		}
		return { right, indexOfMax(mat[right]) };
	}

你可能感兴趣的:(算法,leetcode)