题目:
给定一个未排序的数组,请判断这个数组中是否存在长度为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
代码如上。
不得不说真是奇思妙想,甘拜下风。