数组中的最长山脉

228 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

一、题目

LeetCode 数组中的最长山脉

把符合下列属性的数组 arr 称为 山脉数组 :

arr.length >= 3 存在下标 i(0 < i < arr.length - 1),满足 arr[0] < arr[1] < ... < arr[i - 1] < arr[i] arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 给出一个整数数组 arr,返回最长山脉子数组的长度。如果不存在山脉子数组,返回 0 。

示例 1:

输入:arr = [2,1,4,7,3,2,5]
输出:5
解释:最长的山脉子数组是 [1,4,7,3,2],长度为 5。

示例 2:*

输入:arr = [2,2,2]
输出:0
解释:不存在山脉子数组。

提示:*

1 <= arr.length <= 104
0 <= arr[i] <= 104

二、题解

方法一

山脉数组就像是数组元素值连起来像山一样的,山脉数组中中间那个值就是数组中最大的值为山顶元素,山顶元素往左方向是严格递减的,同样的山顶元素往右方向也是严格递减的,对此我们可以先找到山顶元素,然后再往两边递推就可以了。首先可以定义一个同等大小的数组left,那么left[i]就表示以arr[i]为山顶元素时往左递推符合递减的元素数量;同样的定义一个同等大小的数组right,那么right[i]就表示以arr[i]为山顶元素时往右递推符合递减的元素数量。初始的left[0]arr[0]数组左边无元素所以为0,同样的right[len - 1]arr[len - 1]数组右边无元素也为0。然后先从左到右遍历arr数组元素,以每一个元素arr[i]为山顶元素,如果arr[i - 1] < arr[i]则是符合递减的,所以arr[i]就可以添加一个元素长度即left[i] = left[i - 1] + 1;否则不符合递减就无法组成山脉数组即left[i] = 0。再然后从右到左遍历arr数组元素,以每一个元素arr[i]为山顶元素,如果arr[i] > arr[i + 1]是符合递减的,所以arr[i]就可以添加一个元素长度即right[i] = right[i + 1] + 1;否则不符合递减就无法组成山脉数组即right[i] = 0。最后遍历leftright两个数组,计算以arr[i]为山顶元素时山脉数组的长度,只有当left[i] > 0 && right[i] > 0时才能组成山脉数组,最后保存最长的山脉数组的长度返回。

三、代码

方法一 Java代码

class Solution {
    public int longestMountain(int[] arr) {
        int len = arr.length;
        int[] left = new int[len];
        for (int i = 1; i < len; i++) {
            if (arr[i - 1] < arr[i]) {
                left[i] = left[i - 1] + 1;
            }
        }
        int[] right = new int[len];
        for (int i = len - 2; i >= 0; i--) {
            if (arr[i] > arr[i + 1]) {
                right[i] = right[i + 1] + 1;
            }
        }
        int mountain = 0;
        for (int i = 0; i < len; ++i) {
            if (left[i] > 0 && right[i] > 0) {
                mountain = Math.max(mountain, left[i] + right[i] + 1);
            }
        }
        return mountain;
    }
}

时间复杂度:O(n),需要遍历两次数组元素计算山脉左右两边元素,最后再遍历一次枚举山顶元素计算左右两边长度。

空间复杂度:O(n),需要使用两个同等大小的数组。