300. Longest Increasing Subsequence (LIS)

https://leetcode.com/problems/longest-increasing-subsequence/

1. DP

O(n^2)

Input: [10,9,2,5,3,7,101,18]
Output: 4 
Explanation: The longest increasing subsequence is [2,3,7,101], 
therefore the length is 4. 

ๅพžๅŽŸ้กŒๅฏไปฅ็œ‹ๅ‡บไพ†, ่ฆๆ‰พๅˆฐๆœ€้•ท้žๅขžๅญๅบๅˆ—

ไธ€ๅฎšๆœƒๅŸบๆ–ผๅ‰้ข็š„็‹€ๆ…‹

if (nums[i] > nums[j]) {

dp[i] = Math.max(dp[i], dp[j]+1)

}

  • ๅˆๅง‹็‹€ๆ…‹๏ผš

    • dp[i] ๆ‰€ๆœ‰ๅ…ƒ็ด ็ฝฎ 1๏ผŒๅซ็พฉๆ˜ฏๆฏๅ€‹ๅ…ƒ็ด ้ƒฝ่‡ณๅฐ‘ๅฏไปฅๅ–ฎ็จๆˆ็‚บๅญๅบๅˆ—๏ผŒๆญคๆ™‚้•ทๅบฆ้ƒฝ็‚บ 1ใ€‚

ๆ‰€ไปฅ j ่ฆๅœจ i ๅ‰้ข, nums[i] > nums[j]

time: O(n^2)

space: O(n)

class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums == null && nums.length == 0) return 0;
        
        int dp[] = new int[nums.length];
        Arrays.fill(dp, 1);
        
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    // ไปฃ่กจ i ๆฏ”ๅ‰้ข็š„ j ๅคงๆ™‚, dp[j]+1
                    dp[i] = Math.max(dp[i], dp[j]+1);
                }
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}
/*
 ๅ› ็‚บๆ˜ฏ subseq, ๆ‰€ไปฅไธๆœƒๆœ‰ไป€้บผ -1 ็š„็‹€ๆ…‹, i ่ฆ่ทŸๅ‰้ขๆ‰€ๆœ‰็‹€ๆ…‹้ƒฝๆฏ”้Ž๏ผˆj),
 ็„ถๅพŒๆœ€้•ท็š„็ตๆžœๅฏ่ƒฝๅœจๆŸไบ› dp ่ฃก, ๆ‰€ไปฅ่ฆๅœจๆ‰€ๆœ‰็ตๆžœไธญๆ‰พ max => res = Math.max(res, dp[i]);
*/

time: O(nlogn)

space: O(n)

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] tails = new int[nums.length]; //
        int res = 0;
        for(int num : nums) {
            int i = binarySearch(tails, res, num); // find which index can be smaller (้•ทๅบฆ็‚บ i ็š„ subsequence ็š„ๆœ€ๅฐๅฐพๅทดๅ€ผ
            tails[i] = num; // update smaller num in tails index i
            if(res == i) res++; // if find i == res, means in the last, so it can be longer subsequence

        }
        return res;
    }
    private int binarySearch(int tails[], int res, int num) {
        int left = 0;
        int right = res;
        while (left < right) {
            int mid = left + (right - left)/2;
            if (tails[mid] < num) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}

readable version

class Solution {
    public int lengthOfLIS(int[] nums) {
        int len = 0;
        int tails[] = new int[nums.length];
        
        for (int i = 0; i < nums.length; i++) {
            int num = nums[i];
            
            if (len == 0 || num > tails[len - 1]) {
                tails[len++] = num;
            } else {
                int position = findPositionToReplace(tails, len, num);
                tails[position] = num;
            }
        }
        return len;
    }
    private int findPositionToReplace(int tails[], int res, int num) {
        int left = 0;
        int right = res;
        while (left < right) {
            int mid = left + (right - left)/2;
            if (tails[mid] < num) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}

idea : Patience Sort

https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/

dp[0] means length 1's ็ตๅฐพๆœ€ๅฐ็š„ LIS

dp[1] means length 2 ็ตๅฐพๆœ€ๅฐ็š„ LIS

num: 10

num:10
tails[0]:10
res == j? => j:0, res:0
==============res++=1

num: 9

num:9
cal m i:0, j:1
m:0
else tails[m] >= num, j = m
after i:0, j:0
tails[0]:9
res == j? => j:0, res:1
==============res++=1

num: 2

num:2
cal m i:0, j:1
m:0
else tails[m] >= num, j = m
after i:0, j:0
tails[0]:2
res == j? => j:0, res:1
==============res++=1

num: 5

num:5
cal m i:0, j:1
m:0
tails[m] < num, i = m + 1
after i:1, j:1
tails[1]:5
res == j? => j:1, res:1
==============res++=2

num: 3

num:3
cal m i:0, j:2
m:1
else tails[m] >= num, j = m
after i:0, j:1
cal m i:0, j:1
m:0
tails[m] < num, i = m + 1
after i:1, j:1
tails[1]:3
res == j? => j:1, res:2
==============res++=2

num: 7

num:7
cal m i:0, j:2
m:1
tails[m] < num, i = m + 1
after i:2, j:2
tails[2]:7
res == j? => j:2, res:2
==============res++=3

num: 21

num:21
cal m i:0, j:3
m:1
tails[m] < num, i = m + 1
after i:2, j:3
cal m i:2, j:3
m:2
tails[m] < num, i = m + 1
after i:3, j:3
tails[3]:21
res == j? => j:3, res:3
==============res++=4

num: 18

num:18
cal m i:0, j:4
m:2
tails[m] < num, i = m + 1
after i:3, j:4
cal m i:3, j:4
m:3
else tails[m] >= num, j = m
after i:3, j:3
tails[3]:18
res == j? => j:3, res:4
==============res++=4

tails:[2, 3, 7, 18, 0, 0, 0, 0]

DFS + memo

O(n^2)

```java
class Solution {
    public int lengthOfLIS(int[] nums) {
        Integer[][] memo = new Integer[nums.length][nums.length];
        return dfs(nums, -1, 0, memo);
    }
    private int dfs(int[] nums, int prev, int cur, Integer[][] memo) {
        if (cur == nums.length) {
            return 0;
        }
        if (prev != -1 && memo[prev][cur] != null) {
            return memo[prev][cur];
        }
        int increasing = 0;
        if (prev == -1 || nums[cur] > nums[prev]) {
            increasing = 1 + dfs(nums, cur, cur+1, memo);
        }
        int notIncreasing = dfs(nums, prev, cur+1, memo);
        if (prev != -1) {
            memo[prev][cur] = Math.max(increasing, notIncreasing);
        }
        return Math.max(increasing, notIncreasing);
    }
}
```

Last updated