Let's call any (contiguous) subarray B (of A) a mountain if the following properties hold:

  • B.length >= 3
  • There exists some 0 < i < B.length - 1 such that B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]

(Note that B could be any subarray of A, including the entire array A.)

Given an array A of integers, return the length of the longest mountain.

Return 0 if there is no mountain.

Example 1:

Input: [2,1,4,7,3,2,5]
Output: 5
Explanation: The largest mountain is [1,4,7,3,2] which has length 5.

Example 2:

Input: [2,2,2]
Output: 0
Explanation: There is no mountain.

Note:

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

Follow up:

  • Can you solve it using only one pass?
  • Can you solve it in O(1) space?

这道题给了我们一个数组,然后定义了一种像山一样的子数组,就是先递增再递减的子数组,注意这里是强行递增或者递减的,并不存在相等的情况。那么实际上这道题就是让在数组中寻找一个位置,使得以此位置为终点的递增数组和以此位置为起点的递减数组的长度最大。而以某个位置为起点的递减数组,如果反个方向来看,其实就是就该位置为终点的递增数列,那么既然都是求最长的递增数列,我们可以分别用两个 dp 数组 up 和 down,其中 up[i] 表示以 i 位置为终点的最长递增数列的个数,down[i] 表示以 i 位置为起点的最长递减数列的个数,这样我们正向更新 up 数组,反向更新 down 数组即可。先反向更新好了 down 之后,在正向更新 up 数组的同时,也可以更新结果 res,当某个位置的 up[i] 和 down[i] 均大于0的时候,那么就可以用 up[i] + down[i] + 1 来更新结果 res 了,参见代码如下:

解法一:

class Solution {
public:
int longestMountain(vector<int>& A) {
int res = , n = A.size();
vector<int> up(n), down(n);
for (int i = n - ; i >= ; --i) {
if (A[i] > A[i + ]) down[i] = down[i + ] + ;
}
for (int i = ; i < n; ++i) {
if (A[i] > A[i - ]) up[i] = up[i - ] + ;
if (up[i] > && down[i] > ) res = max(res, up[i] + down[i] + );
}
return res;
}
};

我们可以对空间进行优化,不必使用两个数组来记录所有位置的信息,而是只用两个变量 up 和 down 来分别记录以当前位置为终点的最长递增数列的长度,和以当前位置为终点的最长递减数列的长度。 我们从 i=1 的位置开始遍历,因为山必须要有上坡和下坡,所以 i=0 的位置永远不可能成为 peak。此时再看,如果当前位置跟前面的位置相等了,那么当前位置的 up 和 down 都要重置为0,从当前位置开始找新的山,和之前的应该断开。或者是当 down 不为0,说明此时是在下坡,如果当前位置大于之前的了,突然变上坡了,那么之前的累计也需要重置为0。然后当前位置再进行判断,若大于前一个位置,则是上坡,up 自增1,若小于前一个位置,是下坡,down 自增1。当 up 和 down 同时为正数,则用 up+down+1 来更新结果 res 即可,参见代码如下:

解法二:

class Solution {
public:
int longestMountain(vector<int>& A) {
int res = , up = , down = , n = A.size();
for (int i = ; i < n; ++i) {
if ((down && A[i - ] < A[i]) || (A[i - ] == A[i])) {
up = down = ;
}
if (A[i - ] < A[i]) ++up;
if (A[i - ] > A[i]) ++down;
if (up > && down > ) res = max(res, up + down + );
}
return res;
}
};

我们可以换一种思路,还是一次遍历就行,进行 while 循环,条件是 i < n-1,然后判断,当前数字大于等于下一个数字则跳过,因为我们希望首先上坡,当找到递增的起点i后,则再开始循环,找山顶 peak,找到了之后,再进行下坡,找到山脚j,这样如果i,peak,和j都不相同的话,说明找到了一个完整的山,用 j-i+1 来更新结果 res 即可,然后i从j开始继续遍历,参见代码如下:

解法三:

class Solution {
public:
int longestMountain(vector<int>& A) {
int res = , i = , n = A.size();
while (i < n - ) {
while (i < n - && A[i] >= A[i + ]) ++i;
int peak = i;
while (peak < n - && A[peak] < A[peak + ]) ++peak;
int j = peak;
while (j < n - && A[j] > A[j + ]) ++j;
if (i < peak && peak < j) res = max(res, j - i + );
i = j;
}
return res;
}
};

也可以再换种思路,首先来找山峰,peak 的范围是 [1, n-1],因为首尾两个数字都不能做山峰,能做山峰的位置上的数必须大于其左右两边的数字,然后分别向左右两个方向遍历,这样就可以找到完整的山,用 right-left+1 来更新结果 res,参见代码如下:

解法四:

class Solution {
public:
int longestMountain(vector<int>& A) {
int res = , n = A.size();
for (int i = ; i < n - ; ++i) {
if (A[i - ] < A[i] && A[i + ] < A[i]) {
int left = i - , right = i + ;
while (left > && A[left - ] < A[left]) --left;
while (right < n - && A[right] > A[right + ]) ++right;
res = max(res, right - left + );
}
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/845

参考资料:

https://leetcode.com/problems/longest-mountain-in-array/

https://leetcode.com/problems/longest-mountain-in-array/discuss/176952/Java-1-pass-and-O(1)-space-beats-100

https://leetcode.com/problems/longest-mountain-in-array/discuss/135593/C%2B%2BJavaPython-1-pass-and-O(1)-space

https://leetcode.com/problems/longest-mountain-in-array/discuss/150136/Simple-O(n)-one-pass-O(1)-space-Java-AC-solution-beats-99.05

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Longest Mountain in Array 数组中最长的山的更多相关文章

  1. Longest Mountain in Array 数组中的最长山脉

    我们把数组 A 中符合下列属性的任意连续子数组 B 称为 “山脉”: B.length >= 3 存在 0 < i < B.length - 1 使得 B[0] < B[1] ...

  2. 【LeetCode】845. Longest Mountain in Array 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双数组 参考资料 日期 题目地址:https://l ...

  3. LeetCode第十四题-字符串数组中最长的共同前缀

    Longest Common Prefix 问题简介: 编写一个函数来查找字符串数组中最长的公共前缀字符串,如果没有公共前缀,则返回空字符串"" 举例: 1: 输入: [“xwq” ...

  4. 014 Longest Common Prefix 查找字符串数组中最长的公共前缀字符串

    编写一个函数来查找字符串数组中最长的公共前缀字符串. 详见:https://leetcode.com/problems/longest-common-prefix/description/ 实现语言: ...

  5. LeetCode:寻找旋转排序数组中的最小值【153】

    LeetCode:寻找旋转排序数组中的最小值[153] 题目描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0 ...

  6. [Swift]LeetCode845. 数组中的最长山脉 | Longest Mountain in Array

    Let's call any (contiguous) subarray B (of A) a mountain if the following properties hold: B.length ...

  7. [LeetCode] Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  8. [LeetCode] K-diff Pairs in an Array 数组中差为K的数对

    Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in t ...

  9. [LeetCode] 215. Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

随机推荐

  1. TP5架构下链接SQL数据库的一种方法

    1.database设置 2.连接到所需要的表格 *.数据库目录

  2. C++自己实现一个String类

    C++自己实现一个String类(构造函数.拷贝构造函数.析构函数和字符串赋值函数) #include <iostream> #include <cstring> using ...

  3. 07binlog日志介绍

    设置日志格式为row 创建数据库和表 mysql> create database chinasoft charset=utf8mb4; mysql> use chinasoft; mys ...

  4. tensorflow--交叉熵

    学而不思则罔,思而不学则怠. 最近在看<TensorFlow 实战Google深度学习框架第二版>这本书.从头开始学习深度学习,对于细节方面进行探究.相当于重新拾起来这门”手艺“. 这篇随 ...

  5. 移动端rem与px适应js

    方法一: (function (doc, win) { var docEl = doc.documentElement, resizeEvt = "orientationchange&quo ...

  6. Ubuntu如何安装vncserver

    Ubuntu上安装和配置vncserver,然后通过客户端进行连接,就能够使用图像界面的方式来运行上面的软件了. 1.使用apt-cache search vncserver命令搜索可以用来安装vnc ...

  7. table td中的内容过长,显示为固定长度,多余部分用省略号显示

    简单描述:table数据过长,结果顶到下一格,影响了数据的查看 解决办法: 给table 加上style属性   另外 给td加上style标签修饰 <table class="tab ...

  8. vertx模块DeploymentManager部署管理器

    DeploymentManager public DeploymentManager(VertxInternal vertx) { this.vertx = vertx; loadVerticleFa ...

  9. Linux Centos7.5中的RocketMQ集群部署

    系统环境 Docker > centos7.5 此镜像已经安装了jdk1.8和maven3.6.0 如果你想知道这个基础镜像的具体情况, 参考此文: https://www.cnblogs.co ...

  10. centos6.9 改系统语言成中文简体

    1.在root权限下 切换到root下:su root 查看当前语言环境:locale -a  (注意中间有空格) 如果看到 zh_CN.UTF-8(这个是中文简体)说明你的系统支持中文语言 2.编辑 ...