java solution
class Solution {public int findNumberOfLIS(int[] nums) {//边界情况处理int n = nums.length;if(n <= 1) return n;//然后我们创建2个数组, 分别是count数组和length数组,//length[i]的含义是以i结尾的子数组的最长递增子序列长度//count[i]的含义是以i结尾的子数组的最长递增子序列数量int[] length = new int[n];int[] count = new int[n];Arrays.fill(length, 1); //每个位置结尾的子数组都至少存在长度为1的递增子序列Arrays.fill(count, 1);int maxLen = 1;//开始动态规划for(int i = 1; i < n; i++) {for(int j = 0; j < i; j++) {if(nums[j] < nums[i]) {//两种情况
//情况1. 以j结尾的子数组的最长递增子序列在末尾拼接上nums[i]的长度大于以i结尾的子数组的最长递增子序列if(length[j] + 1 > length[i]) {//更新length数组和count数组length[i] = length[j] + 1;
//继承子序列数量,因为nums[i]是直接拼接在以j结尾的子数组的最长递增子序列的末尾count[i] = count[j]; } else if(length[j] + 1 == length[i]){
//情况2. 以j结尾的子数组的最长递增子序列在末尾拼接上nums[i]的长度等于以i结尾的子数组的最长递增子序列//此时不需要更新leng数组count[i] += count[j];}}}maxLen = Math.max(maxLen, length[i]);}//然后统计最长递增子序列个数int res = 0;for(int i = 0; i < n; i++) {if(length[i] == maxLen) {res += count[i];}}return res; }
}
🧠 题目目标回顾
我们要解决的是:
给定一个未排序的数组
nums
,返回 最长严格递增子序列的个数。
比如:
[1,3,5,4,7]
→ 最长子序列长度是4
,有两种方案[1,3,4,7]
和[1,3,5,7]
→ 输出2
🔍 算法核心思想 —— 动态规划
我们用 动态规划 来解决。
我们需要记录两样东西:
length[i]
:表示以nums[i]
为结尾的 最长递增子序列的长度count[i]
:表示以nums[i]
为结尾的 最长递增子序列的数量
初始化:
- 每个元素自成一个子序列,长度为
1
,个数为1
Arrays.fill(length, 1); Arrays.fill(count, 1);
🧩 动态转移逻辑
遍历每一个位置 i
,再遍历它前面的每一个位置 j
,进行比较:
for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {
当 nums[j] < nums[i]
时,表示可以在 j
的子序列基础上扩展
🧾 两种情况:
✅ 情况1:找到更长的子序列
if (length[j] + 1 > length[i]) {length[i] = length[j] + 1;count[i] = count[j]; // 继承数量
}
比如原来 nums[i]
结尾只有长度为 2
的递增序列,但现在通过 nums[j]
找到了长度为 3
的,说明有了更新:
- 更新
length[i]
- 把
count[j]
赋给count[i]
,因为所有以j
结尾的最长子序列都可以拼到i
上
✅ 情况2:找到等长的子序列
else if (length[j] + 1 == length[i]) {count[i] += count[j]; // 增加方案数
}
说明除了之前的拼法,又找到了另一种拼法也能拼出相同长度的最长子序列,因此把 count[j]
加到 count[i]
上
📌 最后一步:统计所有以最长长度结尾的方案数
我们之前计算了每个位置 i
的最长子序列长度,最后要从中找出最长的,然后把这些位置的方案数加起来:
int res = 0;
for (int i = 0; i < n; i++) {if (length[i] == maxLen) {res += count[i];}
}
⏱️ 时间与空间复杂度
- 时间复杂度:O(n²),两层循环
- 空间复杂度:O(n),两个数组
length[]
和count[]
✅ 举个例子:输入 [1, 3, 5, 4, 7]
i | nums[i] | length[i] | count[i] | 说明 |
---|---|---|---|---|
0 | 1 | 1 | 1 | 初始值 |
1 | 3 | 2 | 1 | 1→3 |
2 | 5 | 3 | 1 | 1→3→5 |
3 | 4 | 3 | 1 | 1→3→4 |
4 | 7 | 4 | 2 | 1→3→4→7 和 1→3→5→7 |
最后返回 count=2,因为有两个长度为 4 的递增子序列。