Skip to content

1. Initial idea

2. Approach

Top-down (memoization)

  • See "solution-topdown.md" for details

Bottom-up (iterative)

  • From the topdown approach, we can see that the state of the subproblem is depended on the prev_index and index as we building up the original 2d memoi table. We calculate the LIS for every index using the first loop to pass index into the recursive function. The following code is from the solution-topdown.md:
    for (int index = 0; index < n; index++) {
        res = max(res, helper(nums, index, n, -1, dp));
    }
  • For every index we passed in, we build a small 1d array memoi table for it, and from that we only use the longest length to calculate the next index. The following lines of code are from solution-topdown.md:
    dp[index][prev_index + 1] = max(take, not_take); // we only update the longest length of the current index into dp
    return dp[index][prev_index+1]; // result of the index passed into recursive function
  • We can also see that, for each current index, the LIS is either the previous LIS+1 (if we can include current value at index) or just LIS if current value do not satisfy the requirement (not_take). For example:
  • With the following testcase: nums = [2,5,3,4]
  • We can see that at index = 0, the LIS = 1; but take a look at index = 1, now we can see that LIS is 2, because we can include 5 into our subsequence
  • Now take a look at index = 2, value = 3 which is smaller than 5, so the LIS at index = 2 is still LIS = 2, which is equal the last LIS before index = 2
  • Now look at index= 3, we can see that before it the LIS is 2 at index = 1 and index = 2, but with the subsequence built upon index = 2 we can include itself to create LIS = 3
  • From all of that, we found the recursive formula, which is LIS(index) = max(LIS(prev_index)) + 1 where nums[prev_index] < nums[index]

Complexity analysis

  • Time complexity: O(n^2) - calculate LIS for every element of the input array
  • Space complexity: O(n) - vector<int> dp is of length n.

3. Implementation

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n, 1);

        for(int index = 1; index < n; index++) {
            for(int prev_index = 0; prev_index < index; prev_index++) {
                if(nums[index] > nums[prev_index]) {// We can consider this LIS(prev_index) to build upon for our LIS(index)
                    dp[index] = max(dp[index], dp[prev_index]+1); // ensure only get the longest LIS(prev_index)
                    // LIS(index) = max(LIS(prev_index)) + 1
                }
            }
        }
        return *max_element(dp.begin(), dp.end());
    }
};