三分搜索峰值

问题

现在有一个数组,显示递增,后是递减,如何找到它的峰值?

思路

可以利用分治的思想,向二分查找一样,每次将要查询的区域分成若干个区域,根据区域的特殊点的值淘汰一些区域,缩小搜索范围,当搜索范围很小时,进行几次比较即可。

那么这个区域怎么分,还有就是怎么淘汰呢?

我们可以考虑将区间[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;
}

  • 20
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值