[leetCode]845. 数组中的最长山脉
csdn:https://blog.csdn.net/renweiyi1487/article/details/109270033
原题地址:https://leetcode-cn.com/problems/longest-mountain-in-array
我们把数组 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。
动态规化
由于从左侧山脚到山顶,与从右侧山脚到山顶是严格单调递增的所以可以使用动态规化。
另$left[i]$表示$A[i]$左侧可以扩展的数量,$right[i]$表示$A[i]$右侧可以扩展的数量,
-
如果$A[i] > A[i-1]$ 那么$left[i]=left[i-1]+1$;如果$i=0则left[i]=0$
-
如果$A[i] > A[i+1]$ 那么$right[i]=right[i+1]+1$;如果$i=n-1则right[i]=0$
计算出所有的$left[],right[]$后就可以枚举山顶,但是需要注意只有当$left[i] > 0 并且 right[i] >0$时A[i]才是山顶。
class Solution {
public int longestMountain(int[] A) {
int n = A.length;
if (n == 0) {
return 0;
}
// left[i] 表示A[i]左侧最多能扩展的数目
int[] left = new int[n];
for (int i = 1; i < n; i++) {
left[i] = A[i] > A[i-1] ? left[i-1]+1 : 0;
}
// right[i] 表示A[i]右侧最多能扩展的数目
int[] right = new int[n];
for (int i = n-2; i >=0; i--) {
right[i] = A[i] > A[i+1] ? 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;
}
}
双指针
定义一个左指针初始值为0指向山脚,每次固定left时需要保证:
- left + 2 < n 因为山脉的长度至少为三
- 然后设置right 指针为left+1,如果left在山脚则控制right指针爬山
- 如果right指针爬到的是山顶则控制right指针下山,然后计算山脉长度,如果right指针爬到的不是山顶则让right指针+1,每寻找一次山脚就要重新固定left
class Solution {
public int longestMountain(int[] A) {
int n = A.length;
if (n == 0) {
return 0;
}
int left = 0, ans = 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 + 1 < n && 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;
}
}