334. 递增的三元子序列

题目:

给定一个未排序的数组,请判断这个数组中是否存在长度为3的递增的子序列。

正式的数学表达如下:

如果存在这样的  i, j, k,  且满足 0 ≤  i <  j <  k ≤  n-1,
使得  arr[i] <  arr[j] <  arr[k] ,返回 true ; 否则返回 false 。

要求算法时间复杂度为O(n),空间复杂度为O(1) 。

示例:
输入 [1, 2, 3, 4, 5],
输出 true.

输入 [5, 4, 3, 2, 1],
输出 false.

刚开始想用递减栈做,结果发现虽然不用O(n^2)遍历,但也是需要跳回原位置进行重新计算。

一看要求,好嘛,绝对是一遍扫描。可是又用什么办法呢?

无奈之下,百度。

发现可以用类似动态规划的方法去做。

原理是动态规划求最长子序列,这下好了,只要求出来的最大长度大于等于3就好咯。

一般情况下的最长子序列长度求法是这样的:

令dp【i】是以nums【i】结尾的最大子序列长度,

转移方程为max{dp【i】|nums【j】<nums【i】,j<i}+1。

通俗来讲,就是在所有j<i的dp【j】中找到nums【i】>nums【j】并且dp【j】+1>dp【i】的。并更新。

这时候可以用一个变量来更新最大的dp。

def LIS(nums):
    dp=[1 for x in range(len(nums))]
    max_len=1
    for i in range(1,len(nums)):
        for j in range(0,i):
            if nums[j]<nums[i] and dp[i]<dp[j]+1:
                dp[i]=dp[j]+1
                max_len=max(max_len,dp[i])
    return max_len

代码如上。

现在回到原题。

首先可以想到的是一旦发现max_len==3就立即停止,返回true。

但是对于那种返回值是false的序列,依旧需要平方的时间。

但是我们可以只用两个变量,first,second.

然后,线性扫描数组,如果小于等于first,赋值给first,如果小于等于second,赋值给second,如果没地方赋值了,说明递增序列中的第三个找到了。

class Solution:
    def increasingTriplet(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        a=b=0x7fffffff
        for n in nums:
            if n<=a:
                a=n
            elif n<=b:
                b=n
            else:
                return True
        return False

代码如上。

不得不说真是奇思妙想,甘拜下风。

猜你喜欢

转载自blog.csdn.net/weixin_37373020/article/details/81096298