[LeetCode 中等]845. 数组中的最长山脉

题目描述

我们把数组 A 中符合下列属性的任意连续子数组 B 称为 “山脉”:

B.length >= 3
存在 0 < i < B.length - 1 使得 B[0] < B[1] < … B[i-1] < B[i] > B[i+1] > … > B[B.length - 1]
(注意:B 可以是 A 的任意子数组,包括整个数组 A。)

给出一个整数数组 A,返回最长 “山脉” 的长度。

如果不含有 “山脉” 则返回 0。

示例 1:

输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。
示例 2:

输入:[2,2,2]
输出:0
解释:不含 “山脉”。

提示:

0 <= A.length <= 10000
0 <= A[i] <= 10000

遍历山顶

时间复杂度 O(n*2)
注意边界处理

class Solution {
    public int longestMountain(int[] A) {
        int len = A.length;
        if(len <3) return 0;
        int res = 0;
        //遍历每个节点 把每个节点当山顶
        for(int i=1;i<len-1;i++){
            int count=0;
            if(A[i-1]<A[i] && A[i]>A[i+1]){
                count = 3;
                int p1 = i-1;
                int p2 = i+1;
                while(p1>0 && A[p1 -1]< A[p1]){
                        p1--;
                        count++;
                }
                while(p2<len-1 && A[p2]> A[p2+1] ){
                        p2++;
                        count++;
                }
            }
            res = Math.max(res,count);
        }
        return res;
    }
}

动态规划

时间复杂度 O(n)
一次遍历

public int longestMountain(int[] A) {
    if(A.length < 3)return 0;
    final int n = A.length;
    int ans = 0;
//一次遍历 用mode来标记是上升还是下降 最符合人脑的思维方式
    int prev = A[0];//初始prev为A[0]
    int start = 0;//一个有效“山脉”的开始位置
    int mode = 0;//0-开始,1-已进入up序列  2-已进入down序列

    for (int i = 1; i < n; i++) {
        if(mode==0) {
            if(A[i] > prev) {
                mode = 1;
                start = i-1;
            }
        } else if(mode == 1) {
            if(A[i] < prev) {
                mode = 2;
            } else if(A[i] == prev) {
                mode = 0;
            }
        } else {
            if(A[i] > prev) {
                mode = 1;
                start = i-1;
            } else if(A[i] == prev) {
                mode = 0;
            }
        }

        // 收集一次答案
        if(mode==2) {
            ans = Math.max(ans, i-start+1);
        }
        prev = A[i];
    }

    return ans;
}

遍历山顶2

class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        if (n == 0) {
            return 0;
        }
// 两个数组 left和right 分别代表递增的left的最高点(山顶) 和递减的right最高点(另一个山顶)
// 最后的最长山脉就是left-right+1
        int[] left = new int[n];
        for (int i = 1; i < n; ++i) {
            left[i] = A[i - 1] < A[i] ? left[i - 1] + 1 : 0;
        }

        int[] right = new int[n];
        for (int i = n - 2; i >= 0; --i) {
            right[i] = A[i + 1] < A[i] ? right[i + 1] + 1 : 0;
        }

        int ans = 0;
        for (int i = 0; i < n; ++i) {
            if (left[i] > 0 && right[i] > 0) {
                ans = Math.max(ans, left[i] + right[i] + 1);
            }
        }
        return ans;
    }
}

遍历山脚

class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        int ans = 0;
        int left = 0;
        
        while (left + 2 < n) {
            int right = left + 1;
            if (A[left] < A[left + 1]) {
                while (right + 1 < n && A[right] < A[right + 1]) {
                    ++right;
                }
                if (right < n - 1 && A[right] > A[right + 1]) {
                    while (right + 1 < n && A[right] > A[right + 1]) {
                        ++right;
                    }
                    ans = Math.max(ans, right - left + 1);
                } else {
                    ++right;
                }
            }
            left = right;
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值