问题
现在有一个数组,显示递增,后是递减,如何找到它的峰值?
思路
可以利用分治的思想,向二分查找一样,每次将要查询的区域分成若干个区域,根据区域的特殊点的值淘汰一些区域,缩小搜索范围,当搜索范围很小时,进行几次比较即可。
那么这个区域怎么分,还有就是怎么淘汰呢?
我们可以考虑将区间[l,r]三等分分为三个区域,[l,mid1]、[mid1,mid2]、[mid2,r]三个区域(暂时不考虑区域重合的问题)。那么mid1,mid2的分布只有四种情况。
1、mid1,mid2都在极值的左边。
2、mid1,mid2都在极值的右边。
3、mid1在左,mid2在右,mid1处的值 > mid2处的值。
4、mid1在左,mid2在右,mid1处的值 <= mid2处的值。
可以用下面这张图概括。
这样我们不断的缩小区间,当区间只有三个或两个点时,比较一下这几个点的值即可。
查找函数
int three_search(int l, int r,int* a)
{
int result = -1;
int maxn = -1;
//不方便分成三个部分的特殊情况
if (l + 2 >= r) {
for(int i=l;i<=r;i++)
if (a[i] > maxn) {
maxn = a[i];
result = i;
}
return result;
}
while (l + 2 < r) {
int dis = (r - l) / 3;
int mid1=l+dis,mid2=r-dis;
if (a[mid1] > a[mid2]) {
r = mid2;
}
else {
l = mid1;
}
}
result=a[l]>a[r]?l:r;
result=a[result]>a[(l+r)>>1]?result:(l+r)>>1;
return result;
}
代码
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100005;
int a[N];
int n,m;
//随机生成一个递增后又递减的数组
void init_array()
{
srand(time(0));
n = rand() % 10000 + 5;
a[0] = rand() % 10;
int pos = rand() % (n - 1);
cout << "n==" << n << ",pos==" << pos << endl;
for (int i = 1; i <= pos; i++) {
a[i] = a[i - 1] + rand() % 10;
}
for (int i = pos + 1; i < n; i++) {
a[i] = a[i - 1] - rand() % 10;
}
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
if (i % 10 == 9) cout << endl;
}
cout << endl;
}
//手动输入一个递增后又递减的数组
void init()
{
cout << "输入一个递增后又递减的数组。\n";
cout << "数组长度:";
cin >> n;
cout << "各项值:";
for (int i = 0; i < n; i++) {
cin >> a[i];
}
}
//三分搜索
int three_search(int l, int r,int* a)
{
int result = -1;
int maxn = -1;
//不方便分成三个部分的特殊情况
if (l + 2 >= r) {
for(int i=l;i<=r;i++)
if (a[i] > maxn) {
maxn = a[i];
result = i;
}
return result;
}
while (l + 2 < r) {
int dis = (r - l) / 3;
int mid1=l+dis,mid2=r-dis;
if (a[mid1] > a[mid2]) {
r = mid2;
}
else {
l = mid1;
}
}
result=a[l]>a[r]?l:r;
result=a[result]>a[(l+r)>>1]?result:(l+r)>>1;
return result;
}
int main()
{
init_array();
int index = three_search(0, n - 1, a);
cout << "最大值索引:" << index << endl;
return 0;
}