该题解使用动态规划来解决最长递增子序列的个数问题。具体思路如下:
1. 使用两个列表dp和count来记录状态。其中dp[i]表示长度为i+1的递增子序列的结尾元素列表,count[i]表示以dp[i]中每个元素结尾的递增子序列个数累计值列表。
2. 遍历给定数组nums中的每个元素num:
a. 二分查找dp中第一个大于等于num的元素位置i。
b. 如果i等于dp的长度,说明num可以接在当前最长递增子序列之后,形成一个新的最长子序列,因此将num添加到dp中,并在count中记录以num结尾的子序列个数为1。
c. 如果i小于dp的长度,说明num可以替换dp[i]中的元素,形成一个新的长度为i+1的递增子序列。此时在dp[i]中二分查找第一个大于num的元素位置k,然后将num添加到dp[i]的末尾,并在count[i]中累加count[i-1][-1] - count[i-1][k],表示以num结尾的递增子序列个数。
3. 最终返回count[-1][-1],即以dp中最后一个元素结尾的递增子序列总数。
时间复杂度: O(n log n)
空间复杂度: O(n)
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
dp, count = [], []
for num in nums:
# 二分查找dp中第一个大于等于num的元素位置i
l, r = 0, len(dp)
while l < r:
mid = (l + r) >> 1
if dp[mid][-1] >= num:
r = mid
else:
l = mid + 1
i = l
c = 1
if i > 0:
# 二分查找dp[i-1]中第一个大于num的元素位置k
l, r = 0, len(dp[i - 1])
while l < r:
mid = (l + r) >> 1
if dp[i-1][mid] < num:
r = mid
else:
l = mid + 1
k = l
# 累加以num结尾的递增子序列个数
c = count[i-1][-1] - count[i-1][k]
if i == len(dp):
# num可以接在当前最长递增子序列之后,形成新的最长子序列
dp.append([num])
count.append([0, c])
else:
# num可以替换dp[i]中的元素,形成新的长度为i+1的递增子序列
dp[i].append(num)
count[i].append(c + count[i][-1])
return count[-1][-1]