其他分享
首页 > 其他分享> > 673. 最长递增子序列的个数

673. 最长递增子序列的个数

作者:互联网

        673. 最长递增子序列的个数

        这道题目是300. 最长递增子序列的进阶版。

        解决代码如下:

from bisect import bisect_left
class Solution(object):
    def findNumberOfLIS(self, nums):
        dp = [nums[0]]
        dp1 = [{nums[0] : 1}]
        for i in nums[1 : ]: 
            if i > dp[-1]:
                dp.append(i)
                dp1.append({i : 0})
                for key,value in dp1[-2].items():
                    if i > key:
                        dp1[-1][i] += value
            else:
                pos = bisect_left(dp, i)
                dp[pos] = i
                if i not in dp1[pos]:
                    dp1[pos][i] = 0
                if pos == 0:
                    dp1[0][i] += 1
                else:
                    for key, value in dp1[pos - 1].items():
                        if i > key:
                            dp1[pos][i] += value
        res = 0
        for value in dp1[-1].values():
            res += value
        return res

原理:

        维护dp和dp1数组

        dp数组索引 i 处记录的是当前构成长度为 i+1 的递增子序列的最小末尾数

        dp1和dp很类似,但是dp1索引 i 处记录的是应该字典,字典中记录的是当前所有长度为 i+1 的子序列,当它们末尾数为key时,有value种构成的方式(key必须构成尽量长的子序列,例如以7为末尾数时,最长能构成长度为3的子序列)

        对nums数组遍历

        比如 nums = [10,9,2,5,3,7,21,18]

        当遍历到nums[6] = 21时:

        因为构成长度为1的子序列有[10],[9],[2],[5],[3],[7],最小的末尾数是2

        构成长度为2的子序列有[2,5],[2,3],[2,7],[3,7],[5,7],最小的末尾数是3

        构成长度为3的子序列有[2,5,7]和[2,3,7],最小的末尾数是7

        所以此时dp = [2,3,7]

        因为dp是一个单调递增的数组,当遍历到nums[n](记为num)时,如果num > dp[-1],就在dp末尾插入num,否则,用bisect模块中的bisect_left函数,定位num应该在dp中插入的位置pos,然后更新

        注意不是把num插入到dp[pos]位置,而是将dp[pos]更新为num

        例如当遍历到nums[7] = 18时,此时dp = [2,3,7,21],定位18在dp中的位置,pos = 3,所以dp[3] = 18,dp = [2,3,7,18]

        接下来是如何维护dp1

        当遍历到nums[5] = 7(记为num)时:

        此时dp1 = [{10:1, 9:1, 2:1}, {5:1, 3:1}]

        由pos可知,当num为7时,最长的子序列长度变成了3,所以要在dp1末尾插入一个新的字典,这个字典新增key = 7,value = 当前长度为2的子序列,且末尾数小于7(这里有2和5)的key所对应的value之和 1+1=2 

        同理当遍历到nums[7] = 18 时:

        此时dp1 = [{10:1, 9:1, 2:1}, {5:1, 3:1}, {7:2}, {21:2}]

        由pos可知,18应该作为key添加到子序列长度为4的字典里面,即dp1[3],value等于当前子序列长度为3,且末尾数小于18(只有dp1[3][7])的key所对应的value之和 2

        当遍历完nums数组以后,dp1[-1]中的全部value加起来,就是所要求的最长递增子序列的个数

     

标签:dp1,nums,递增,个数,pos,value,673,序列,dp
来源: https://blog.csdn.net/m0_56015193/article/details/120403518