2021-02-08

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))

提交结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值