在算法研究中,序列问题是一个常见而重要的主题。最长递增子序列问题不仅在理论上具有挑战性,同时在许多实际应用中也非常有用,如数据分析、动态规划和计算机视觉等领域。本文将深入探讨如何利用动态规划和计数技巧来解决该问题,同时提供 Python 和 C++ 的具体实现,以帮助读者更好地理解和掌握这一算法。

给定一个整数数组 nums,我们需要找到其中最长的递增子序列的长度,以及该长度的递增子序列的个数。
・ 定义 dp[i] 为以 nums[i] 结尾的最长递增子序列的长度, count[i] 为以 nums[i] 结尾的最长递增子序列的个数。
・递推关采如下:
・对于每个 nums[i],音看其前面的所有元素 nums[j]( j < i ):
nums[j] < nums[i], 则更新 dp[i] : ,说明找到了一个更长的递增子序列,更新 count[i] 为 count[j]。
,说明找到了一个同样长度的递增子序列,累加 count[j] 到 count[i]。
和 count, 长度与 nums 相同:
dp[i] 初始化为 1,因为每个元素本身可以形成长度为 1 的递增子序列。count[i]初始化为 1 ,因为毎个元素自身的子序列个数为 1 。nums,更新 dp[i] 和 count[i]数组。 来获取最长递增子序列的长度,并对 count 数组进行遍历,累加所有 count[i] (当 dp[i] 等于最长长度) 以获得该长度子序列的个数。
数组的构建,使时间复杂度降低到
。
count。
bisect 库可以方便地在 tails 中找到合适的位置,并更新计数,进一步提高效率。以上就是最长递增子序列的个数问题的基本思路。
class Solution:
def findNumberOfLIS(self, nums):
if not nums:
return 0
n = len(nums)
dp = [1] * n # 初始化 dp 数组
count = [1] * n # 初始化 count 数组
for i in range(n): # 遍历每个元素
for j in range(i): # 检查前面的元素
if nums[j] < nums[i]: # 如果找到较小的元素
if dp[j] + 1 > dp[i]: # 找到更长的递增子序列
dp[i] = dp[j] + 1
count[i] = count[j] # 更新个数
elif dp[j] + 1 == dp[i]: # 找到相同长度的递增子序列
count[i] += count[j] # 累加个数
max_length = max(dp) # 获取最长递增子序列的长度
return sum(count[i] for i in range(n) if dp[i] == max_length) # 返回该长度的个数dp 和 count 数组,分别存储最长递增子序列的长度和个数。dp 和 count 数组。max(dp),然后累加所有 count[i](当 dp[i] 等于最大长度)以获得结果。class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
if (nums.empty()) return 0;
int n = nums.size();
vector<int> dp(n, 1); // dp[i] 表示以 nums[i] 结尾的最长上升子序列的长度
vector<int> count(n, 1); // count[i] 表示以 nums[i] 结尾的最长上升子序列的个数
int max_length = 0; // 记录最长上升子序列的长度
int max_count = 0; // 记录最长上升子序列的个数
// 动态规划计算 dp 和 count 数组
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1; // 更新长度
count[i] = count[j]; // 更新个数
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j]; // 追加个数
}
}
}
max_length = max(max_length, dp[i]); // 更新最大长度
}
// 计算最长上升子序列的总个数
for (int i = 0; i < n; ++i) {
if (dp[i] == max_length) {
max_count += count[i]; // 统计个数
}
}
return max_count; // 返回结果
}
};dp[i] 用于存储以 nums[i] 结尾的最长上升子序列的长度。count[i] 用于存储以 nums[i] 结尾的最长上升子序列的个数。max_length 和 max_count 分别用于记录最长上升子序列的长度和个数。i,内层循环遍历 i 之前的所有元素 j。nums[i] 大于 nums[j],检查是否形成了更长的上升子序列。dp[i] 和 count[i];如果找到了相同长度的序列,增加 count[i]。dp 数组,统计最长上升子序列的总个数。