题意描述
定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1],又有arr[i]<arr[i+1],那么arr[i]是局部最小。给定无序数组arr,已知arr中任意两个相邻的数都不相等。写一个函数,只需返回arr中任意一个局部最小出现的位置即可。
思路描述
- 我们判断0位置是不是局部最小,如果是直接返回,如果不是我们判断N-1位置上是不是局部最小,如果是直接返回,如果不是进行第二步
- 如果来到该步骤,那么一定面对的数组类似下图
可以看出中间部分一定存在局部最小。
3. 我们取待判断区间的中点位置,看看它是不是局部最小,如果是则返回,如果不是选择其与相邻元素为下降趋势的一边作为待判断的数组。对于7所在位置,如下图,我们可以判断在该中点位置到数组末尾一定存在局部最小
4. 重复第三步
对于2所在中点,我们可以发现不满足,继续重复第三步。
对于1所在中点,我们可以发现满足条件,直接返回。
总结
并不是非要有序才能二分,只有当在某一种标准下,如果可以判断一边一定有,或者另一边一定没有的时候就可以二分。
示例代码
#include <iostream>
#include <queue>
#include <functional>
#include <string>
using namespace std;
int partialMinFind(vector<int> &arr)
{
if (arr.size() < 2)
{
return arr[0];
}
if (arr[0] < arr[1])
{
return arr[0];
}
if (arr[arr.size() - 2] > arr[arr.size() - 1])
{
return arr[arr.size() - 1];
}
int left = 0;
int right = arr.size() - 1;
while (1)
{
int mid = left + ((right - left) >> 1);
if (arr[mid] < arr[mid + 1] && arr[mid] < arr[mid - 1])
{
return arr[mid];
}
if (arr[mid] > arr[mid + 1])
{
left = mid;
}
else if (arr[mid] > arr[mid - 1])
{
right = mid;
}
}
}
int main(int argc, char ** argv)
{
vector<int> arr{ 5,2,4,1,7,5,2,1,4,5 };
int res = partialMinFind(arr);
cout << res << endl;
system("pause");
return EXIT_SUCCESS;
}