Number of Longest Increasing Subsequence - Complete Solution Guide
Number of Longest Increasing Subsequence is LeetCode problem 673, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
Given an integer array nums , return the number of longest increasing subsequences. Notice that the sequence has to be strictly increasing. Example 1: Input: nums = [1,3,5,4,7] Output: 2 Explanation: The two longest increasing subsequences are [1, 3, 4, 7] and [1, 3, 5, 7]. Example 2: Input: nums = [2,2,2,2,2] Output: 5 Explanation: The length of the longest increasing subsequence is 1, and there are 5 increasing subsequences of length 1, so output 5. Constraints: 1 <= nums.length <= 2000 -10 6
Detailed Explanation
The problem asks us to find the number of Longest Increasing Subsequences (LIS) within a given integer array `nums`. An increasing subsequence is a sequence of numbers within the array that are strictly increasing (nums[i] < nums[j] for i < j). We need to return how many such subsequences have the maximum possible length. The input array can have any integers, including duplicates, and its length can range from 1 to 2000.
Solution Approach
The provided code employs a dynamic programming approach. It iterates through the input array `nums` and, for each element `nums[i]`, it considers all preceding elements `nums[j]` (where `j < i`). If `nums[j] < nums[i]`, it means `nums[i]` can potentially extend an increasing subsequence ending at `nums[j]`. The `lengths` array stores the length of the LIS ending at each index, and the `counts` array stores the number of such LISs. The algorithm maintains the `max_len` and `result` variables to track the overall maximum LIS length and the number of LISs with that length. After processing all elements, the `result` will contain the desired count.
Step-by-Step Algorithm
- Step 1: Initialize two arrays, `lengths` and `counts`, each with the same size as the input array `nums`. Initialize all elements of `lengths` to 1 (as each element itself forms an LIS of length 1) and all elements of `counts` to 1 (as there's initially one LIS of length 1 ending at each index).
- Step 2: Initialize `max_len` to 0 and `result` to 0. These variables will store the maximum LIS length found so far and the number of LISs with that maximum length.
- Step 3: Iterate through the input array `nums` from index `i = 0` to `n-1`.
- Step 4: For each `i`, iterate through the preceding elements `nums[j]` from index `j = 0` to `i-1`.
- Step 5: If `nums[j] < nums[i]` (i.e., `nums[i]` can extend the subsequence ending at `nums[j]`):
- a. If `lengths[j] + 1 > lengths[i]` (extending the subsequence at `j` results in a longer LIS at `i`): Update `lengths[i]` to `lengths[j] + 1` and `counts[i]` to `counts[j]` (because all LISs ending at `i` are now extensions of LISs ending at `j`).
- b. Else if `lengths[j] + 1 == lengths[i]` (extending the subsequence at `j` results in an LIS of the same length at `i`): Add `counts[j]` to `counts[i]` (because we found additional LISs of the same length ending at `i`).
- Step 6: After processing all `j` for a given `i`, update `max_len` and `result`:
- a. If `lengths[i] > max_len`: Update `max_len` to `lengths[i]` and `result` to `counts[i]` (we found a new longest LIS).
- b. Else if `lengths[i] == max_len`: Add `counts[i]` to `result` (we found additional LISs of the maximum length).
- Step 7: After processing all elements in `nums`, return `result`.
Key Insights
- Insight 1: Dynamic Programming is suitable because the LIS problem exhibits optimal substructure. The LIS ending at index `i` can be built from the LIS ending at earlier indices.
- Insight 2: We need to track both the length of the LIS ending at each index and the number of such LISs. Two arrays, `lengths` and `counts`, are crucial.
- Insight 3: When building an LIS, if extending a previous subsequence results in a longer subsequence at the current index, we update both the length and count. If it results in a subsequence of the same length, we add the count of the previous subsequence to the current count.
Complexity Analysis
Time Complexity: O(n^2)
Space Complexity: O(n)
Topics
This problem involves: Array, Dynamic Programming, Binary Indexed Tree, Segment Tree.
Companies
Asked at: Commvault, Intuit.