[LeetCode] 300. Longest Increasing Subsequence (C++)


Source of subject: https://leetcode-cn.com/problems/longest-increasing-subsequence/

Title description

Give you an integer array nums and find the length of the longest strictly increasing subsequence.

A subsequence is a sequence derived from an array, deleting (or not deleting) elements in the array without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].

Example 1:
Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], so the length is 4.
Example 2:
Input: nums = [0,1,0,3,2,3]
Output: 4
Example 3:
Input: nums = [7,7,7,7,7,7,7]
Output: 1
Tip:
1 <= nums.length <= 2500
10^4 <= nums[i] <= 10^4
Advanced:
Can you design a solution with a time complexity of O(n2)?
Can you reduce the time complexity of the algorithm to O(n log(n))?

General idea

  • The classic application problem of dynamic programming, find the longest strictly monotonic subsequence, and the subsequence does not require continuous, but there is a sequence. The idea of ​​greedy + binary search often appears in dynamic programming. First define the state of the problem
    dp [i] = max (dp [j] + 1), where 0 ≤ j ≤ i, and num [j] <num [i] dp[i]=max(dp[j]+1), where 0 ≤ j ≤ i, and num [j] <num[i]dp[i]=max(dp[j]+1 ) , which the 0ji , and n u m [ j ] < n u m [ i ]

Dynamic programming O(n^2)

After nested loops available, if DP [j] is 2, is equivalent to the index j , the length of the already constitutes a strictly monotonic subsequences 2, the subscript i upon expansion, only at this time is determined Whether j is satisfied, nums[j]<nums[i], if the condition is satisfied, expand to i, update dp[i], note that dp[j]+1 is compared with dp[i], and dp[ i] The length that has been included in a certain subsequence at this time

class Solution {
    
    
public:
    int lengthOfLIS(vector<int>& nums) {
    
    
        int len = nums.size(), ans = 0;
        vector<int> dp(len, 1);
        for(int i = 0 ; i < len ; ++i){
    
    
            for(int j = 0 ; j < i ; ++j){
    
    
                if(nums[j] < nums[i])
                    dp[i] = max(dp[j] + 1, dp[i]);
            }
        }
        return *max_element(dp.begin(), dp.end());
    }
};

Complexity analysis

  • Time complexity: O(n^2). Approximately nested traversal array
  • Space complexity: O(n). n is the size of the array

Greedy + binary search

  • For strictly monotonic subsequences, we can maintain a dp array. According to the above reasoning, we can get the algorithm flow
  • Suppose the length of the longest ascending subsequence that has been found currently is len (the initial value is 1), and the array nums is traversed from the front to the back. When traversing to nums[i]:
    • If num[i]>dp[len], add directly to the end of the dp array and update len=len+1
    • Otherwise, binary search in the dp array, find the first number d[k] smaller than nums[i], and update d[k+1]=nums[i]

Take the input sequence [0, 8, 4, 12, 2] as an example: the
first step is to insert 0, dp = [0]; the
second step is to insert 8, dp = [0, 8]; the
third step is to insert 4, dp = [0, 4];
Insert 12 in the fourth step, dp = [0, 4, 12];
Insert 2, in the fifth step, dp = [0, 2, 12].
Finally, the maximum incremental subsequence length is 3.

class Solution {
    
    
public:
    int lengthOfLIS(vector<int>& nums) {
    
    
        int len = nums.size();
        vector<int> dp(len + 1, 0);
        int index = 1;
        dp[1] = nums[0];
        for(int i = 1 ; i < len ; ++i){
    
    
            if(dp[index] < nums[i]){
    
    
                dp[++index] = nums[i];
            }else{
    
    
                int left = 1, right = index, result = -1;
                while(left <= right){
    
    
                    int mid = right + ((left - right) >> 1);
                    if(dp[mid] < nums[i])  left = mid + 1;
                    else{
    
    
                        if(mid == 0 || dp[mid - 1] < nums[i]){
    
    
                            result = mid;
                            break;
                        }
                        else    right = mid - 1;
                    }
                }
                dp[(result != -1) ? result : 1] = nums[i];
            }
        }
        return index;
    }
};

Complexity analysis

  • Time complexity: O(nlogn). The average time complexity of binary search is O(nlogn), where n is at worst equal to array n
  • Space complexity: O(n).

Guess you like

Origin blog.csdn.net/lr_shadow/article/details/114366278