Longest Increasing Subsequence
Patience-sort tails — for each value, replace the leftmost tail ≥ it; final tail length is LIS.
3 min read
dp binary-search patience-sort
Problem#
Return the length of the longest strictly-increasing subsequence.
Examples#
[10,9,2,5,3,7,101,18]→4(one such:[2,3,7,101]).[0,1,0,3,2,3]→4;[7,7,7,7]→1.
Constraints#
1 <= nums.length <= 2500.
Approach#
Maintain a sorted tails array where tails[k] is the smallest possible tail of any increasing subsequence of length k+1. For each value, binary-search the first tail >= value and replace it (or append if larger than all).
Solution#
class Solution {public: int lengthOfLIS(vector<int>& nums) { vector<int> tails; for (int x : nums) { auto it = lower_bound(tails.begin(), tails.end(), x); if (it == tails.end()) tails.push_back(x); else *it = x; } return tails.size(); }};import "sort"
func lengthOfLIS(nums []int) int { tails := []int{} for _, x := range nums { i := sort.SearchInts(tails, x) if i == len(tails) { tails = append(tails, x) } else { tails[i] = x } } return len(tails)}import bisectfrom typing import List
class Solution: def lengthOfLIS(self, nums: List[int]) -> int: tails: List[int] = [] for x in nums: i = bisect.bisect_left(tails, x) if i == len(tails): tails.append(x) else: tails[i] = x return len(tails)function lengthOfLIS(nums) { const tails = []; for (const x of nums) { let lo = 0, hi = tails.length; while (lo < hi) { const mid = (lo + hi) >> 1; if (tails[mid] < x) lo = mid + 1; else hi = mid; } if (lo === tails.length) tails.push(x); else tails[lo] = x; } return tails.length;}class Solution { public int lengthOfLIS(int[] nums) { int[] tails = new int[nums.length]; int size = 0; for (int x : nums) { int lo = 0, hi = size; while (lo < hi) { int mid = (lo + hi) >>> 1; if (tails[mid] < x) lo = mid + 1; else hi = mid; } tails[lo] = x; if (lo == size) size++; } return size; }}function lengthOfLIS(nums: number[]): number { const tails: number[] = []; for (const x of nums) { let lo = 0, hi = tails.length; while (lo < hi) { const mid = (lo + hi) >> 1; if (tails[mid] < x) lo = mid + 1; else hi = mid; } if (lo === tails.length) tails.push(x); else tails[lo] = x; } return tails.length;}Editorial#
tails is not necessarily a real subsequence — it just tracks the best possible tail per length. Patience sort is the conceptual model: each tails[k] is the top of the k-th pile. The trick is that the answer is just the pile count.
Complexity#
- Time:
O(n log n). - Space:
O(n).
Concept revision#
Related#