# 673. Number of Longest Increasing Subsequence
LeetCode Problem Link (opens new window)
Given an unsorted array of integers, find the number of longest increasing subsequences.
Example 1:
- Input: [1,3,5,4,7]
- Output: 2
- Explanation: There are two longest increasing subsequences, [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:
- Input: [2,2,2,2,2]
- Output: 5
- Explanation: The longest increasing subsequence length is 1, and there are 5 subsequences of length 1, so output 5.
# Approach
This problem can be considered as an advanced version of 0300.Longest Increasing Subsequence (opens new window).
- Define the dp array (dp table) and the meaning of indices
For this problem, we maintain two arrays together.
dp[i]: The length of the longest increasing subsequence up to and including index i is dp[i].
count[i]: The number of the longest increasing subsequences ending with nums[i] is count[i].
- Define the transition formula
In the problem of 0300. Longest Increasing Subsequence, we established the state transition as:
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
That is: the length of the longest increasing subsequence for position i is equal to the maximum value of j from 0 to i-1 using their longest increasing subsequences plus one.
This problem is more complex, as we need to consider two dimensions: updating dp[i] and updating count[i].
How do we update count[i]?
Given a sequence ending with nums[i], the number of the longest increasing subsequences is count[i].
Thus, given nums[i] > nums[j], if within range [0, i-1], we find j such that dp[j] + 1 > dp[i], it indicates we found a longer increasing subsequence. Therefore, the number of longest increasing subsequences ending with j is the latest count of the longest increasing subsequences ending with i, i.e., count[i] = count[j].
Given nums[i] > nums[j], if within range [0, i-1], we find j such that dp[j] + 1 == dp[i], it implies there are two increasing subsequences of the same length. Thus, the number of longest increasing subsequences ending with i should be increased by the number of longest increasing subsequences ending with j, i.e., count[i] += count[j].
The code is as follows:
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
dp[i] = max(dp[i], dp[j] + 1);
}
2
3
4
5
6
7
8
You can also write it like this:
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1; // Update dp[i] here, no need for max anymore
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
}
2
3
4
5
6
7
8
Here count[i] records the number of longest increasing subsequences ending with nums[i]. dp[i] tracks the length of the longest increasing subsequence up to i (inclusive).
To find the number of longest increasing subsequences, we should keep a record of the maximum length.
The code is:
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > maxCount) maxCount = dp[i]; // Record the max length
}
}
2
3
4
5
6
7
8
9
10
11
12
13
- Initialize the dp array
Review the definitions of dp[i] and count[i].
count[i] records the number of the longest increasing subsequences ending with nums[i].
At the minimum, this is 1, so initialize count[i] to 1.
dp[i] records the length of the longest increasing sequence up to and including i.
The minimum length is also 1, so initialize dp[i] to 1.
The code is:
vector<int> dp(nums.size(), 1);
vector<int> count(nums.size(), 1);
2
Initialization in dynamic programming problems is very crucial and tests the understanding of the dp array's definition.
- Determine the traversal order
dp[i] is derived from the longest increasing subsequence of each position from 0 to i-1, so we must traverse i from front to back.
j traverses from 0 to i-1, with i as the outer loop and j as the inner loop. Code is:
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > maxCount) maxCount = dp[i];
}
}
2
3
4
5
6
7
8
9
10
11
12
13
Finally, traverse dp[i] again. Accumulate count[i] that corresponds to the length of the longest increasing sequence, which is the result.
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) {
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > maxCount) maxCount = dp[i];
}
}
int result = 0; // Gather the result
for (int i = 0; i < nums.size(); i++) {
if (maxCount == dp[i]) result += count[i];
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Revisit dp[i] and count[i] definition if the calculation seemed confusing.
- Example walkthrough of the dp array
Input: [1,3,5,4,7]

If the code doesn't work no matter what you try, print the dp and count arrays to check if they are correct!
Analysis complete, here is the full C++ code:
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
vector<int> dp(nums.size(), 1);
vector<int> count(nums.size(), 1);
int maxCount = 0;
for (int i = 1; i < nums.size(); 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];
}
}
if (dp[i] > maxCount) maxCount = dp[i];
}
}
int result = 0;
for (int i = 0; i < nums.size(); i++) {
if (maxCount == dp[i]) result += count[i];
}
return result;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- Time Complexity: O(n^2)
- Space Complexity: O(n)
There is also an O(n log n) solution using a Fenwick tree. I am busy today and won’t write it up, but interested students can learn about it themselves here: Here are the Fenwick tree series blogs I wrote earlier (opens new window) (Decade-old archived texts).
# Other Language Versions
# Java
class Solution {
public int findNumberOfLIS(int[] nums) {
if (nums.length <= 1) return nums.length;
int[] dp = new int[nums.length];
for(int i = 0; i < dp.length; i++) dp[i] = 1;
int[] count = new int[nums.length];
for(int i = 0; i < count.length; i++) count[i] = 1;
int maxCount = 0;
for (int i = 1; i < nums.length; 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];
}
}
if (dp[i] > maxCount) maxCount = dp[i];
}
}
int result = 0;
for (int i = 0; i < nums.length; i++) {
if (maxCount == dp[i]) result += count[i];
}
return result;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Python
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
size = len(nums)
if size<= 1: return size
dp = [1 for i in range(size)]
count = [1 for i in range(size)]
maxCount = 0
for i in range(1, size):
for j in range(i):
if nums[i] > nums[j]:
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]
if dp[i] > maxCount:
maxCount = dp[i];
result = 0
for i in range(size):
if maxCount == dp[i]:
result += count[i]
return result;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Go
func findNumberOfLIS(nums []int) int {
size := len(nums)
if size <= 1 {
return size
}
dp := make([]int, size);
for i, _ := range dp {
dp[i] = 1
}
count := make([]int, size);
for i, _ := range count {
count[i] = 1
}
maxCount := 0
for i := 1; i < size; i++ {
for 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]
}
}
if dp[i] > maxCount {
maxCount = dp[i]
}
}
}
result := 0
for i := 0; i < size; i++ {
if maxCount == dp[i] {
result += count[i]
}
}
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# JavaScript
var findNumberOfLIS = function(nums) {
const len = nums.length;
if(len <= 1) return len;
let dp = new Array(len).fill(1); // The longest increasing subsequence up to and including i is dp[i]
let count = new Array(len).fill(1); // The number of the longest increasing subsequences ending with nums[i]
let res = 0;
for(let i = 1; i < len; i++){
for(let j = 0; j < i; j++){
if(nums[i] > nums[j]){
if(dp[j] + 1 > dp[i]){ // Sequence length with nums[j] as the previous element could be longer
dp[i] = dp[j] + 1; // Update dp[i]
count[i] = count[j]; // Reset count[i]
} else if(dp[j] + 1 === dp[i]){ // Equal to existing length
count[i] += count[j]; // Update count[i]
}
}
}
}
let max = Math.max(...dp); // Spread operator to find maximum length
for(let i = 0; i < len; i++) if(dp[i] === max) res += count[i]; // Accumulate
return res;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22