最长递增子序列的变种:最长递增子序列的个数
字数 1522 2025-10-30 21:15:36
最长递增子序列的变种:最长递增子序列的个数
题目描述
给定一个整数数组 nums,我们需要找出最长递增子序列(LIS)的长度,并统计所有可能的最长递增子序列的个数。注意,子序列不要求连续,但必须严格递增。例如,对于输入 [1,3,5,4,7],最长递增子序列的长度是 4(如 [1,3,4,7] 和 [1,3,5,7]),因此最长递增子序列的个数是 2。
解题过程
-
问题分析
- 基础问题:使用动态规划求最长递增子序列长度。定义
dp_len[i]表示以nums[i]结尾的最长递增子序列长度。 - 新增目标:统计最长递增子序列的个数。需要额外定义
dp_count[i]表示以nums[i]结尾的最长递增子序列的个数。
- 基础问题:使用动态规划求最长递增子序列长度。定义
-
状态定义
dp_len[i]:以nums[i]结尾的 LIS 长度。dp_count[i]:以nums[i]结尾的 LIS 的个数。
-
状态转移
- 初始化:每个元素自身构成长度为 1 的子序列,因此
dp_len[i] = 1,dp_count[i] = 1。 - 遍历
i从 0 到 n-1,对于每个i,遍历j从 0 到 i-1:- 如果
nums[j] < nums[i],说明nums[i]可以接在以nums[j]结尾的子序列后:- 若
dp_len[j] + 1 > dp_len[i]:更新dp_len[i] = dp_len[j] + 1,并重置dp_count[i] = dp_count[j]。 - 若
dp_len[j] + 1 == dp_len[i]:说明找到相同长度的新路径,累加个数,dp_count[i] += dp_count[j]。
- 若
- 如果
- 初始化:每个元素自身构成长度为 1 的子序列,因此
-
统计结果
- 遍历所有
dp_len[i],找到最大值max_len。 - 将所有
dp_len[i] == max_len对应的dp_count[i]相加,得到最长递增子序列的总个数。
- 遍历所有
-
示例演算(以
nums = [1,3,5,4,7]为例)- 初始化:
dp_len = [1,1,1,1,1],dp_count = [1,1,1,1,1]。 - i=1(元素3):
- j=0(1<3):
dp_len[1]=2,dp_count[1]=1。
- j=0(1<3):
- i=2(元素5):
- j=0(1<5):
dp_len[2]=2,dp_count[2]=1。 - j=1(3<5):
dp_len[2]=3(更新),dp_count[2]=1。
- j=0(1<5):
- i=3(元素4):
- j=0(1<4):
dp_len[3]=2,dp_count[3]=1。 - j=1(3<4):
dp_len[3]=3(更新),dp_count[3]=1。 - j=2(5≥4,跳过)。
- j=0(1<4):
- i=4(元素7):
- j=0(1<7):
dp_len[4]=2,dp_count[4]=1。 - j=1(3<7):
dp_len[4]=3,dp_count[4]=1。 - j=2(5<7):
dp_len[4]=4(更新),dp_count[4]=1。 - j=3(4<7):
dp_len[4]=4(相同长度),dp_count[4]=1+1=2。
- j=0(1<7):
- 最终:
max_len=4,对应i=4的dp_count[4]=2,故答案为 2。
- 初始化:
-
复杂度分析
- 时间复杂度:O(n²),需要双层循环遍历所有元素对。
- 空间复杂度:O(n),用于存储两个 dp 数组。
通过以上步骤,我们同时得到了最长递增子序列的长度和个数。