Problem
LeetCode 673. Number of Longest Increasing Subsequence
1. 题目简述
给出一个未排序的整形数组,返回其最长递增系序列的数量。例如:
Example 1:
Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
Note:
数据规模不会超过2000且保证最终的解是32位整形数
2. 算法思路
相关问题:
和300题不同的是,这里我们需要返回的是数量,而不是长度,也就是说仅仅找出长度已经无法满足我们的需求,我们不仅需要记录长度,还需要记录数量。
另一种思路是使用segement tree,暂时还没学到那块,等学到了在回头看!!!
动态规划
我们需要记录的有两个数值,到当前数字截止的最长的递增子序列长度和数量。因此,这是一个二维dp问题。对于300题中的第二种解法我们可以抛弃了,因为它只能找出长度,而无法找到数量。
因此,我们记录一个二维dp数组,每一维数组都有两个值,一个是长度,一个是数量。
当我们向前一个个查找的时候,记录最长的递增子序列的数量。
时间复杂度为O(n ^ 2),因为每次都要去找前面所有的数字,很慢。
class Solution {
public int findNumberOfLIS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
// dp[i][0]表示到当前的最长长度,dp[i][1]表示当前最长长度的数量;初始化dp[0][0] = 0, dp[0][1] = 1。
int n = nums.length;
int[][] dp = new int [n][2];
for (int i = 0; i < n; i++) {
dp[i][0] = 1;
}
dp[0][1] = 1;
int maxLength = 1;
for (int i = 1; i < n; i++) {
// 这里需要注意!!!count需要初始化为1,因为假设说前面都没有比它小的,那么它就不会进入循环,它自己本身就是一个序列。
int count = 1, longestLength = 1;
for (int j = 0; j < i; j++) {
// 只有当前面数字比当前数字小的时候才会进行判断
if (nums[j] < nums[i]) {
if (longestLength < dp[j][0] + 1) {
count = dp[j][1];
longestLength = dp[j][0] + 1;
} else if (longestLength == dp[j][0] + 1) {
count += dp[j][1];
}
}
}
dp[i][0] = longestLength;
dp[i][1] = count;
maxLength = Math.max(maxLength, longestLength);
}
// 根据最长长度遍历dp数组,记录总的最长长度数量
int res = 0;
for (int i = 0; i < n; i++) {
if (dp[i][0] == maxLength) {
res += dp[i][1];
}
}
return res;
}
}