最长递增子序列的个数
字数 1446 2025-11-02 10:11:13
最长递增子序列的个数
题目描述
给定一个整数数组 nums,找到最长递增子序列(LIS)的长度,并返回不同最长递增子序列的个数。注意:序列必须是严格递增的,且两个序列被视为不同,只要它们选取的元素下标不同(即使元素值相同)。
解题思路
这个问题需要同时解决两个问题:
- 找到最长递增子序列的长度
- 统计所有最长递增子序列的数量
我们需要设计一个动态规划方案,既能记录每个位置结尾的最长递增子序列长度,又能记录对应的序列数量。
详细解题步骤
步骤1:定义状态
我们定义两个数组:
length[i]:表示以第i个元素结尾的最长递增子序列的长度count[i]:表示以第i个元素结尾的最长递增子序列的个数
步骤2:状态初始化
对于每个位置i,初始时:
length[i] = 1(最短的递增子序列就是只包含自己)count[i] = 1(只有一种方式:只选择自己)
步骤3:状态转移方程
对于每个位置i,我们需要检查所有j < i:
- 如果
nums[j] < nums[i](满足递增条件):- 如果
length[j] + 1 > length[i]:- 更新
length[i] = length[j] + 1 - 重置
count[i] = count[j]
- 更新
- 如果
length[j] + 1 == length[i]:- 累加
count[i] += count[j]
- 累加
- 如果
步骤4:寻找全局最优
遍历完成后,我们需要:
- 找到最大的
length[i]值(即最长递增子序列的长度) - 将所有
length[i]等于最大长度的count[i]累加起来
步骤5:示例演示
以数组[1, 3, 5, 4, 7]为例:
初始化:
- length = [1, 1, 1, 1, 1]
- count = [1, 1, 1, 1, 1]
处理过程:
- i=0:第一个元素,保持不变
- i=1:比较nums[0]=1 < nums[1]=3
- length[1] = max(1, 1+1) = 2
- count[1] = count[0] = 1
- i=2:比较前两个元素
- nums[0]=1 < 5:length[2] = 2, count[2] = 1
- nums[1]=3 < 5:length[2] = 3, count[2] = 1
- i=3:比较前三个元素
- nums[0]=1 < 4:length[3] = 2, count[3] = 1
- nums[1]=3 < 4:length[3] = 3, count[3] = 1
- nums[2]=5 > 4:不满足条件
- i=4:比较前四个元素
- nums[0]=1 < 7:length[4] = 2, count[4] = 1
- nums[1]=3 < 7:length[4] = 3, count[4] = 1
- nums[2]=5 < 7:length[4] = 4, count[4] = 1
- nums[3]=4 < 7:length[4] = 4, count[4] = 2
最终结果:
- 最大长度:4
- 总数量:count[4] = 2
步骤6:算法实现
def findNumberOfLIS(nums):
if not nums:
return 0
n = len(nums)
length = [1] * n # 以i结尾的最长递增子序列长度
count = [1] * n # 以i结尾的最长递增子序列数量
for i in range(n):
for j in range(i):
if nums[j] < nums[i]:
if length[j] + 1 > length[i]:
length[i] = length[j] + 1
count[i] = count[j]
elif length[j] + 1 == length[i]:
count[i] += count[j]
max_length = max(length)
result = 0
for i in range(n):
if length[i] == max_length:
result += count[i]
return result
时间复杂度分析
- 时间复杂度:O(n²),需要两层循环遍历
- 空间复杂度:O(n),需要两个长度为n的数组
这个算法通过动态规划同时跟踪长度和数量,有效地解决了最长递增子序列的计数问题。