1、题目描述
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。
输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。
输入:[2,2,2]
输出:0
解释:不含 “山脉”。
2、代码详解
法一:双指针,中心向两侧扩张
剪枝前
class Solution(object):
def longestMountain(self, A):
"""
:type A: List[int]
:rtype: int
"""
n = len(A)
if not A or n <= 2:
return 0
n_max = 0
for i in range(1, n-1): #
if A[i-1] < A[i] and A[i] > A[i+1]:
left = i - 1 # 以i为山顶的左山底
right = i + 1 # 以i为山顶的右山底
while left > 0 and A[left-1] < A[left]: # 向左找山底
left -= 1
while right < n-1 and A[right+1] < A[right]: # 向右找山底
right += 1
n_max = max(n_max, (right-left+1))
return n_max
剪枝后(i可以直接移到right位置)
class Solution(object):
def longestMountain(self, A):
"""
:type A: List[int]
:rtype: int
"""
n = len(A)
if not A or n <= 2:
return 0
n_max = 0
i = 1 # 剪枝
while i < n-1: # 剪枝
if A[i-1] < A[i] and A[i] > A[i+1]:
left = i - 1 # 以i为山顶的左山底
right = i + 1 # 以i为山顶的右山底
while left > 0 and A[left-1] < A[left]: # 向左找山底
left -= 1
while right < n-1 and A[right+1] < A[right]: # 向右找山底
right += 1
n_max = max(n_max, (right-left+1))
i = right # 剪枝
else:
i += 1 # 剪枝
return n_max
时间复杂度小于O(n*n),这种做法也是O(n)的,因为那种有n个数量级的点都可能成为答案的时候,左右能扩出去的长度是很有限的。每个点也只会被访问有限次
法二:左右双指针,正序遍历一次,逆序遍历一次
山脉的长度为 left+right[i]+1
class Solution(object):
def longestMountain(self, A):
"""
:type A: List[int]
:rtype: int
"""
if not A:
return 0
n = len(A)
left = [0] * n
for i in range(1, n):
if A[i] > A[i-1]:
left[i] = left[i-1] + 1
else:
left[i] = 0
right = [0] * n
for i in range(n-2, -1, -1):
if A[i] > A[i+1]:
right[i] = right[i+1] + 1
else:
right[i] = 0
n_max = 0
print(left)
print(right)
for i in range(n):
if left[i] > 0 and right[i] > 0:
n_max = max(n_max, left[i]+right[i]+1)
return n_max
- 时间复杂度:O(n),其中 n 是数组长度
- 空间复杂度:O(n),即为数组left 和right 空间