2021-2-8 Leetcode每日刷题
题目
当 A 的子数组 A[i], A[i+1], …, A[j] 满足下列条件时,我们称其为湍流子数组:
- 若 i <= k < j,当 k 为奇数时, A[k] > A[k+1],且当 k 为偶数时,A[k] < A[k+1];
- 或 若 i <= k < j,当 k 为偶数时,A[k] > A[k+1] ,且当 k 为奇数时, A[k] < A[k+1]。
也就是说,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是湍流子数组。
返回 A 的最大湍流子数组的长度。
示例一
输入:[9,4,2,10,7,8,8,1,9]
输出:5
解释:(A[1] > A[2] < A[3] > A[4] < A[5])
示例二
输入:[4,8,12,16]
输出:2
示例三
输入:[100,100,100]
输出:1
提示
1 <= A.length <= 40000
0 <= A[i] <= 10^9
我的思路
首先考虑分类,当数组长度大于2的时候考虑除去开头和结尾的每个数字左右符号是否不同且不为0,判断方式为相减再相乘是否小于0。记下连续小于0的最长片段的长度,一旦不符合则重置。
但是仅考虑数组长度是不够的,还需要考虑到数组重复元素,因此使用set()去重后:
- 如果元素个数为0,1无论数组长度多长都返回元素个数
- 如果元素个数为2且数组长度为2则返回2
- 如果元素个数为2但数组长度大于2则需要按照上述方法计算
- 如果元素个数大于2数组长度必大于2需要按照上述方法计算
总之,分两类:数组长度大于二且元素个数大于等于2按照上述方法计算,否则返回元素个数。
class Solution:
def maxTurbulenceSize(self, arr: List[int]) -> int:
l = len(arr)
arr1 = list(set(arr))
n = len(arr1)
if l>2 and n>=2:
lens = 2 #初始为2,包括最前和最后的数字
maxlens = 2
for i in range(1,l-1):
if (arr[i-1]-arr[i]) * (arr[i]-arr[i+1]) < 0: #必须符号不同且不为0才行
lens+=1
if lens> maxlens:
maxlens = lens
else:
lens = 2
return maxlens
else:
return n
提交结果
参考思路
思路一:滑动窗口
设窗口[left,right]内部是一个湍流子数组,窗口向右移动,要考虑下一个窗口的位置。
- 当right左边右边符号不等的时候,right可以移动到right+1。
- 否则,说明right-1和right+1无法构成湍流子数组,left移动到right。
当滑动窗口大小为1即left=right的时候,如果right不等于right+1,那么right可以右移。否则left和right同时右移。
每移动一次窗口,记录下当前窗口大小并于最大窗口大小比较,取最大值进行下一次比较。
class Solution:
def maxTurbulenceSize(self, arr: List[int]) -> int:
l = len(arr)
left = 0
right = 0
ret = 1
while right<l-1:
if left == right:
if arr[right] != arr[right+1]:
right +=1
else:
left+=1
right+=1
else:
if (arr[right-1]-arr[right]) * (arr[right]-arr[right+1]) < 0:
right+=1
else:
left = right
ret = max(ret,right-left+1)
return ret
提交结果:
复杂度分析
- 时间复杂度:O(n),其中 n 为数组的长度。窗口的左右端点最多各移动 n 次。
- 空间复杂度:O(1)。只需要维护常数额外空间。
思路二:动态规划
这个官方解释没看懂,负雪明烛做的图讲的非常清楚。
动态规划首先需要定义状态是什么,再写出状态转移方程。
对于最大连续子数组问题,最合适的方法是动态规划。通常设定状态dp[i]表示指针指向i时以i结尾的最长连续子数组长度。这样定义的dp[i]可以反应i以及i之前的区间的情况。只需要考虑dp[i]以及arr[i],arr[i+1]的情况就可以更新状态dp[i+1]。
对于本题只设定一个状态是不够的,要考虑到i位置数组在增大还是在降低,需要设定两个状态up[i],down[i]加以区分。
- 定义 up[i] 表示以位置 i 结尾的,并且 arr[i - 1] < arr[i] 的最长湍流子数组长度。
- 定义 down[i] 表示以位置 i 结尾的,并且 arr[i - 1] > arr[i] 的最长湍流子数组长度。
up[i] 和 down[i] 初始化都是 1,因为每个数字本身都是一个最小的湍流子数组。
状态转移方程:
- up[i] = down[i - 1] + 1,当 arr[i - 1] < arr[i];
- down[i] = up[i - 1] + 1,当 arr[i - 1] > arr[i];
代码(真的好短!):
class Solution:
def maxTurbulenceSize(self, arr: List[int]) -> int:
l = len(arr)
up = [1]*l
down = [1]*l
for i in range(1,l):
if arr[i-1]<arr[i]:
up[i] = down[i-1]+1
down[i] = 1
if arr[i-1]>arr[i]:
up[i] = 1
down[i] = up[i-1]+1
return max(max(down),max(up))
提交结果: