300. Longest Increasing Subsequence (LIS)

https://leetcode.com/problems/longest-increasing-subsequence/arrow-up-right

1. DP

O(n^2)

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

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

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)

time: O(nlogn)

space: O(n)

Latest

Explaination:

๐Ÿ” Goal of Leetcode 300

Given an array nums[], return the length of the longest increasing subsequence (LIS). The brute-force or DP approach is O(n2)O(n^2)O(n2). But this solution runs in O(nlogโกn)O(n \log n)O(nlogn) using binary search.


โœ… Core Idea (High-level)

Maintain a list dp, where:

  • dp[i] is the smallest possible tail of an increasing subsequence of length i + 1.


๐Ÿง  Why this works:

Letโ€™s say we build subsequences ending at:

This means:

  • We have an increasing subsequence of length 3 ending with 9

  • If a new number 6 comes in, we could replace 9 with 6 (making it easier to extend future subsequences)

So the idea is: always keep dp as optimized as possible, replacing with smaller values if we can.


โœจ Breakdown of the code:

๐Ÿ”น dp.add(nums[0]);

Start with the first number โ€” weโ€™ve found a subsequence of length 1.

๐Ÿ”น For each nums[i]:

  1. If itโ€™s smaller than everything so far:

    โ†’ Replace the first element (start new possible LIS).

  2. If it's larger than the last element:

    โ†’ Extend the LIS.

  3. Otherwise:

    โ†’ Find the first element in dp greater than or equal to nums[i] and replace it to keep the sequence tail as small as possible.


๐Ÿ” About binarySearch(dp, num)

Your version of binarySerach() is slightly more complicated than necessary. The goal is to find the first element โ‰ฅ num.

Hereโ€™s a cleaner and more standard version:

This returns the leftmost index where dp.get(index) >= num, which is what we want to replace.


๐Ÿงช Example:

nums = [10, 9, 2, 5, 3, 7, 101, 18]

Step-by-step dp:

Final dp.size() = 4, so LIS = 4.


โœ… Final Notes

  • dp doesn't store an actual LIS, just helps track the length.

  • The trick is: we only replace, never remove โ€” the dp list is always valid.


Let me know if youโ€™d like to adapt this code to recover the actual LIS sequence, or if you want a visual animation of how it builds!

4o

You said:

but seems 2, 3, 7, 18 is a LIS?

ChatGPT said:

Yes! You're absolutely right โ€” in the example:

One possible Longest Increasing Subsequence (LIS) is:

And that's exactly what the algorithmโ€™s dp ends up with at the end:


๐Ÿ” Important clarification:

The dp list does not always represent an actual LIS from the array, but:

It always maintains a list such that:

  • Its length equals the length of the LIS,

  • And the values are the smallest possible ending values for increasing subsequences of various lengths.


๐Ÿง  Why this matters:

The real LIS might use different elements from the original array โ€” this greedy + binary search method only gives you the length, not necessarily the actual sequence.

In this case, dp = [2, 3, 7, 18] does happen to be a valid LIS, but:

  • Thatโ€™s a coincidence โ€” it won't always reconstruct the actual sequence.

  • It's just a helpful structure to find the length efficiently in O(nlogโกn)O(n \log n)O(nlogn).


๐Ÿงช Counter-example:

Step-by-step dp:

  • 3 โ†’ [3]

  • 5 โ†’ [3, 5]

  • 7 โ†’ [3, 5, 7]

  • 1 โ†’ [1, 5, 7] โ† replaced 3 with 1

  • 2 โ†’ [1, 2, 7]

  • 8 โ†’ [1, 2, 7, 8]

Final dp = [1, 2, 7, 8] LIS length = 4 โœ” But [3, 5, 7, 8] is also a valid LIS โ€” dp doesn't give the original one.


โœ… Summary

  • Yes, in your case dp = [2, 3, 7, 18] is a valid LIS.

  • But thatโ€™s not guaranteed โ€” dp is a tool to get the LIS length, not necessarily the actual sequence.

Would you like to see how to recover the actual LIS in O(nlogโกn)O(n \log n)O(nlogn)?

readable version

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/arrow-up-right

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

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

num: 10

num: 9

num: 2

num: 5

num: 3

num: 7

num: 21

num: 18

DFS + memo

O(n^2)

Last updated