一.问题描述
Given an unsorted array of integers, find the number of longest increasing subsequence.
Example 1:
Input: [1,3,5,4,7] Output: 2 Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:
Input: [2,2,2,2,2] Output: 5 Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.
Note: Length of the given array will be not exceed 2000 and the answer is guaranteed to be fit in 32-bit signed int.
二.解题思路
额,很明显又是一道动态规划题,最近写动态规划题目写的我都要怀疑人生了。。。
动态规划主要还是确定递推的规则
先分析一下题目,
假如我知道从数组的[0,k]中最长的子序列长度是t,个数是m
来分析一下把数组的array[k+1]加进去考虑的时候会发生什么事情
我们只要知道最长的子序列的个数,所有首先考虑什么情况下会给变最长子序列的个数
第一个是:最长子序列的长度+1,这种情况下,最长子序列的个数等于之前所有子序列长度为m的序列中,array[k+1]大于那个子序列的最大值
第二个是:最长子序列的长度不变,个数增加,这种情况就比较复杂,增加的子序列的个数是,(1)之前子序列长度为m-1的序列中,array[k+1]大于那个子序列的最大值;或者(2)在子序列长度为m的序列中,array[k+1]等于那个子序列的最大值,此时子序列的最大值等于m加上满足上述条件的子序列的个数
不管是哪个情况,改变的条件都是要当前的数作为一个序列的结尾,它不能做结尾的时候不能改变任何东西,而做结尾的条件就是它要比之前的数大。
因此,这道题需要两个数组
len[i]: 以数组开始到以num[i]为结尾(注意,是以num[i]为子序列的结尾)的最长子序列长度
cnt[i]:以数组开始到以num[i]为结尾(注意,是以num[i]为子序列的结尾)的最长子序列长度的个数
同时每次迭代maxlen记录最长的序列的长度,res用来记录以maxlen为最长度的序列个数
我们来看看具体怎么迭代的:
当k->k+1时,
我们要比较0~k范围内的数和array[k+1]的值大小,因为之前提到了,array[k+1]结尾才能改变东西
如果数比array[k+1]大,我们不用做处理
如果比array[k+1]小,这是我们重点关注了
首先,如果len[i]+1=len[k+1],这符合我们第二种情况的(1),我们让cnt[k+1]=cnt[k+1]+cnt[i]
如果len[i]+1>len[k+1],len[k+1]=len[i]+1,意思就是把自己加到末尾,cnt[k+1]=cnt[i],对应第一种情况
可能有人会问第二种情况的(2)呢
这是在实现的时候取巧自动处理,利用maxlen和res
如果len[k+1]==maxlen ,res=res+cnt[i] 如果历史最大长度和当前的最大长度相等,说明对应的是情况二
否则 res=cnt[i],对应情况1
迭代的时候,如果array[k+1]==array[i] 并且len[k+1]==len[i]==maxlen, 想想是啥情况
res在之前就已经加上了len[i]的cnt[i],所以不用特地在主程序里去判断情况2的(2),当然你要特地去处理也很简单
价格array[k+1]==array[i]的判断就好了
说实话文字描述动态规划还挺痛苦的,没有天赋做老师啊
更多leetcode算法题解法请关注我的专栏leetcode算法从零到结束或关注我
欢迎大家一起套路一起刷题一起ac
三.源码
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
# len[i]: the length of the Longest Increasing Subsequence which ends with nums[i].
# cnt[i]: the number of the Longest Increasing Subsequence which ends with nums[i].
if nums==[]:
return 0
length=len(nums)
lens,cnt=[0]*length,[0]*length
maxlen=0
lens[0],cnt[0],res=1,1,0
for i in range(length):
lens[i],cnt[i]=1,1
for t in range(0,i):
if nums[i]>nums[t]:
if lens[i]>lens[t]+1:continue
if lens[i]==lens[t]+1:cnt[i]+=cnt[t]
else:
lens[i]=lens[t]+1
cnt[i]=cnt[t]
if maxlen==lens[i]:res+=cnt[i]
elif maxlen<lens[i]:
maxlen=lens[i]
res=cnt[i]
else:pass
return res