[MIT6.006 算法导论] 1. Peak Finding 寻峰

一、1D情况

假设有一个如下图的一维数组,格子下的数字代表它们的索引位置,格子内的字母代表该位置内的数值。

峰值的定义:当且仅当 b≥a 且 b≥c 时,位置2为峰值。(如果位置位于数组两个边界,则只需要比较另一个方向。如当 a≥b 时,位置1为峰值。)

寻峰:如果峰值存在,找到峰值所在的位置。(注意,由于定义时使用了大于等于,在此定义下数组内必定至少存在一个位置满足峰值的定义,因此此时不需要考虑峰值不存在的情况)
在这里插入图片描述

1、遍历

最简单且最直接的峰值寻找方式就是遍历,遍历数组内的每一个位置,若该位置内的元素满足峰值定义,则该位置就是峰值。

时间复杂度:O(n),在最坏的情况下需要访问数组内的每一个元素。

2、二分(分治思想)

二分寻找峰值法主要步骤(假设数组为a,长度为n):

  • 找到中间位置数值 a[ n 2 \frac{n}{2} 2n]
  • if a[ n 2 \frac{n}{2} 2n] < a[ n 2 − 1 \frac{n}{2}-1 2n1],数值变化如下图所示,在 a[ n 2 \frac{n}{2} 2n] 左边肯定会存在峰值,则在左边 1 到 n 2 − 1 \frac{n}{2}-1 2n1 内寻找峰值
  • else if a[ n 2 \frac{n}{2} 2n] < a[ n 2 + 1 \frac{n}{2}+1 2n+1],也就是说,a[ n 2 − 1 \frac{n}{2}-1 2n1] 已经小于或者等于 a[ n 2 \frac{n}{2} 2n] 了,数值变化如下图所示。在 a[ n 2 \frac{n}{2} 2n] 右边肯定会存在峰值,则在右边 n 2 + 1 \frac{n}{2}+1 2n+1 到 n 内寻找峰值
  • else 位置 n 2 \frac{n}{2} 2n 就是峰值

时间复杂度:O( l o g 2 n log_2n log2n

刷题正好碰到(leetcode 852. 山脉数组的峰顶索引),补上C++代码实现:
需要留意 m i d = = 0 mid==0 mid==0 m i d = = a r r . s i z e ( ) − 1 mid==arr.size()-1 mid==arr.size()1 时两种情况

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int l=0;
        int r=arr.size()-1;

        while(l<r)
        {
            int m=(l+r)/2;
            if(m==0)
            {
                if(arr[m]<arr[m+1])
                {
                    l=m+1;
                }
                else return m;
            }

            if(m==arr.size()-1)
            {
                if(arr[m]<arr[m-1])
                {
                    r=m-1;
                }
                else return m;
            }

            if(m!=0 && m!=arr.size()-1)
            {
                if(arr[m]<arr[m-1])
                {
                    r=m-1;
                }
                else if(arr[m]<arr[m+1])
                {
                    l=m+1;
                }
                else return m;
            }
            
        }

        return r;
    }
};

二、2D情况

假设有一个如下图的二维数组。

峰值的定义:当且仅当 a≥b 且 a≥c 且 a≥d 且 a≥e 时,a所在位置为峰值。
在这里插入图片描述

同样有两种方法找到峰值所在位置

1、贪心上升

在某个开始位置执行贪心算法,在该位置处,向上下左右四个方向中,上升度最高的方向移动。若四个方向的上升度都小于等于0,则所在位置为峰值。
在这里插入图片描述
贪心算法执行举例:在12处,上升度分别为向左的1,向下的-1。最高的是13所在的左方向,所以向左移动到达13。同理13处继续向左移动到达14。整个移动过程最终到达20,即为该二维数组的峰值。

时间复杂度:O(mn),在最坏的情况下,贪心算法可能需要走遍整个二维数组内的每一个元素,所以时间复杂度是O(mn)

2、分治

  • 找到中间列 j = m/2

  • 遍历 j 列, 找到 j 列中最大的元素 (i, j)

  • if (i,j-1)>(i,j),选择左边部分,1 列到 j-1 列,重复以上步骤。

  • else if (i,j+1)> (i,j),到这一步条件判断已经意味着(i,j-1)≤ (i,j),选择右边部分,j+1 列到 m 列,重复以上步骤

  • else 到这一步条件判断意味着(i,j)左边右边均小于或等于它,而(i,j)又是 j 列中最大的元素,所以(i,j)是二维数组的峰值

时间复杂度:O(n l o g 2 m log_2m log2m),遍历列寻找最大值时的时间复杂度为O(n),选择列时使用了二分的方式,时间复杂度为O( l o g 2 m log_2m log2m

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值