- 最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
解题思路:
序列a=[10,9,2,5,3,7,101,18,20]
方法一 :动态规划
思路:先选择一个数字,如选择7,则7 前面上升是2 3 7或者2 5 7,即到7为止最长子序列的长度为3
第一步:状态转移方程
DP[i] 表示从0->i元素,且要把i元素要选上,的最长子序列的长度。(如上面选择的7,则DP[i]为3)
**问题转换为求:**Max(DP[0]、DP[1]…DP[n-1]) 即LIS length =max(dp[i]),其中0≤i<n
如DP[0]是10,最长上升序列为10
DP[1]是9, 最长上升序列为9
DP[2]是2, 最长上升序列为2
DP[3]是5, 最长上升序列为2 5
DP[4]是3, 最长上升序列为2 5 或2 3
DP[5]是7, 最长上升序列为2 3 7或2 5 7
DP[6]是101, 最长上升序列为2,3,7,101或2,5,7,101
DP[7]是18, 最长上升序列为2 3 7 18或2,5,7,18
DP[8]是20, 最长上升序列为2 3 7 18 20 或2 5 7 18 20
所以Max(DP[0]、DP[1]…DP[n-1])即Max([1, 1, 1, 2, 2, 3, 4, 4, 5]) 是5
第2步:状态转移方程DP[i]
for i i范围为0->n-1
DP[i]=Max{DP[j]+1} =Max{DP[j]}+1 注:j范围是0->i-1且a[j]<a[i] 意思是j是i前面的数所以j的范围是[0,i-1],又因为要求是上升子序列所以需要a[j]<a[i],a[i]为7则a[j]可以是2 5 3但不可以是10 9;+1这个1指的是a[i]这个元素本身如是7
即2层循环
i:0->n-1:
j:0->i-1:
求DP[i]
所以时间复杂度是O(N平方)
def lengthOfLIS(nums):
if not nums:
return 0
dp = []
for i in range(len(nums)):
print("====i:",i)
dp.append(1)
for j in range(i):
print("**j:", j)
if nums[i] > nums[j]:
print("i:%s,dp[i]:%s"%(i,dp[i]))
print("j:%s,dp[j]:%s"%(j,dp[j]))
dp[i] = max(dp[i], dp[j] + 1)#这里+1的1指的是第i个元素本身,意思是
#当如当i为5时,即元素是7,则满足if条见j取2、3、4对应的元素为2、5、3
#则dp[5]=max(dp[5],dp[2]+1,dp[3]+1,dp[4]+1)
#dp[i] = max(dp[j] + 1)这么写是不对的
print("last i:%s,dp[i]:%s"%(i,dp[i]))
print("i&&:",dp)
print(dp)#[1, 1, 1, 2, 2, 3, 4, 4, 5]
return max(dp)
nums=[10,9,2,5,3,7,101,18,20]
a=lengthOfLIS(nums)
print(a)#5