Given an unsorted array of integers, find the number of longest increasing subsequence.
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].
Example 2:
Input: [2,2,2,2,2] Output: 5 Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.
Note: Length of the given array will be not exceed 2000 and the answer is guaranteed to be fit in 32-bit signed int.
这道题明显是leetcode300. Longest Increasing Subsequence的变体。LIS是在最一个序列里找到最长的递增子序列的长度。
example: [84, -48, -33, -34, -52, 72, 75, -12, 72, -45]
- scan from left to right, the longest that ends at 84: [84] (1)
- ... ends at -48: [-48] (1)
- ... ends at -33: [-48, -33] (2)
- ... ends at -34: [-48, -34] (2)
- ... ends at -52: [-52] (1)
- ... ends at 72: [-48, -33, 72] or [-48, -34, 72] (3)
- ... ends at 75: [-48, -33, 72, 75] or [-48, -34, 72, 75] (4)
- ... ends at -12: [-48, -33, -12] or [-48, -34, 12] (3)
- ... ends at 72: [-48, -33, -12, 72] or [-48, -34, 12, 72] (4)
- ... ends at -45: [-48, -45], [-52,-45] (2)
通过观察我们可以发现,当我们寻找第i个位置的最长子序列长度时是通过遍历位置i左边所有数值小于nums[i]的位置,找出当中对应长度最大的一个,然后取那个数加1(相当于nums[i]续在它所能续(它必须比它想续的序列的最后一个位置的数大)的序列中的最长一条),我们用dp[i]记录位置当序列结束在位置i时,该序列的最大长度。
所有的元素都能自成一条序列,因此用1初始化dp数组。
dp[i] = max{dp[j]+1 | nums[i] > nums[j] }
解题思路:LIS的变体要求输出最长子序列的个数,因此我为每个位置增加一个变量dp[i].second来记录状态转移的方程中max{dp[j]+1}有多少个j同时符合跳转要求。
从当前位置往回扫描的过程中,一旦发现有比当前发现的最长“可续”序列更长的序列时,更新max值,更新from值。from值记录的是要多少条符合max值的子序列。如果发现是相同长度序列(即max值相等), 则from要在原基础上加上当前位置所能代表的几条子序列。
如果在往回扫描的过程中,并没有可续的子序列,则from值为0,dp[i].second不变保持为1。如果有可续的,则dp[i].second更新为from值所记录的条数。
int findNumberOfLIS(vector<int>& nums) {
// dp[i].first: the length of the longest increasing subsequence ends at string[i]
vector<pair<int, int>> dp(nums.size(),make_pair(1, 1));
int ans = 1;
for (int i = 1; i < nums.size(); i++) {
int max = 0; // 用于更新左边符合要求的最长子序列的长度
int from = 0;
for (int j = i-1; j >= 0; j--) {
if (nums[i] > nums[j]) {
if (dp[j].first > max) {
max = dp[j].first;
from = dp[j].second;
} else if (dp[j].first == max) {
from += dp[j].second;
}
}
}
if (max != 0) {
dp[i].first += max;
dp[i].second = from;
}
// 最长子序列的长度更新
if (dp[i].first > ans) ans = dp[i].first;
}
if (ans == 1) return dp.size();
int sum = 0;
for (int i = 0; i < dp.size(); i++) {
if (dp[i].first == ans) {
sum += dp[i].second;
}
}
return sum;
}