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. Hibernate-注解

    一, 为啥用注解 Hibernate注解使得原本放在xml文件中的信息直接表现在类中 为什么要用注解呢,因为注解可以简洁快速地在编写代码的同时实现映射关系 注解的好处就是语言简洁,即插即用.  坏处就 ...

  2. 【Android手机测试】OOM

    当大多数应用程序都消耗完自己的内存的时候,因为这些应用程序的内存需求加起来超出了物理内存(包括swap)的容量,内核(OOM killer)必须杀掉一些进程才能腾出空间保障系统正常运行 Linux内核 ...

  3. 管理外部表(External Tables)

    Oracle数据库允许对外部表中的数据进行只读访问.外部表定义为不驻留在数据库中的表,并且可以是为其提供访问驱动程序的任何格式.通过为数据库提供描述外部表的元数据,数据库能够公开外部表中的数据,就好像 ...

  4. 统计信息不准导致sql性能下降

    某局的预生产系统一条sql语句20分钟执行完,上线以后2个小时没执行出来,在预生产执行计划是hash join在生产是nested loop,通过awr基表wri$_optstat_tab_histo ...

  5. pycharm远程调试服务器

    1.下载专业版pycharm并激活 https://blog.csdn.net/weixin_39332299/article/details/79692283 2.创建项目,设置解释器时,选择SSH ...

  6. PHP-高并发和大流量的解决方案

    一  高并发的概念在互联网时代,并发,高并发通常是指并发访问.也就是在某个时间点,有多少个访问同时到来. 二  高并发架构相关概念1.QPS (每秒查询率) : 每秒钟请求或者查询的数量,在互联网领域 ...

  7. 解决exlipse下 springboot 错误:找不到或无法加载主类

    简单描述:控制台出现了下图 废话不多说,直接上解决办法: 方法一:如果你很有自信,自己的pom 没问题,并且已经加载了所有依赖的jar.ok,这是eclipse的问题,window=>prefe ...

  8. @PostConstruct 和 @PreConstruct

    1.从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct和@PreDestroy,这两个注解被用来修饰一个非静态的void()方法.写法 ...

  9. 编译php-5.3.28

    1. 下载php-5.3.28 2. 编译/安装 ./configure --prefix=/usr/local/php --enable-fpm --enable-maintainer-zts -- ...

  10. 学习HTML5, Canvas及简单动画的使用

    通过在CSDN中的一些简单课程学习,跟随老师联系,做了如下的月亮,太阳和地球的运动效果.纪录在文章中,用于下次使用. 准备工作如下: 1. 使用三张背景图片 太阳 月亮 地球 2. 在HTML页面中定 ...