Skip to content
AI360Xpert
Beta
Difficulty: Medium1-D Dynamic Programming

Longest Increasing Subsequence

Problem in Plain English

Given an integer array, find the length of the longest subsequence whose values rise strictly from left to right.

Problem Statement

You are given an integer array nums. A subsequence keeps some elements in their original order while deleting the rest.

Return the length of the longest subsequence that is strictly increasing. The subsequence itself need not be contiguous, and equal values never extend a strictly rising run.

Constraints

  • 1≤nums.length≤25001 \leq \text{nums.length} \leq 2500
  • −104≤nums[i]≤104-10^4 \leq \text{nums}[i] \leq 10^4

Examples

Example 1

Input
nums = [3, 1, 2]
Output
2

Skip 3 and keep indices 1 and 2, giving [1, 2]. Keeping 3 prevents either later pick, and the entire array is not increasing, so the maximum length is 2.

Example 2

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

Indices 2, 4, 5 and 6 give [2, 3, 7, 101]; choosing index 7 instead of 6 also gives [2, 3, 7, 18]. A length-5 subsequence is impossible: after choosing 2, at most one of 5 and 3 can be kept, followed by 7 and at most one of 101 and 18.

Example 3

Input
nums = [0, 1, 0, 3, 2, 3]
Output
4

Indices 0, 1, 4 and 5 give [0, 1, 2, 3]. The earlier 3 at index 3 must be skipped to use the later 2. Repeated 0 and 3 values cannot themselves extend a strictly increasing subsequence, so the answer is 4.

Example 4

Input
nums = [7, 7, 7, 7, 7, 7, 7]
Output
1

No pair of positions has a strictly larger second value. Every single 7 is valid, but adding another 7 would violate strict increase, so the answer is 1.

Example 5

Input
nums = [-10000]
Output
1

The sole negative value forms a subsequence of length 1. A starting sentinel of 0 would incorrectly forbid this value; an index of -1 represents no previous pick.

Intuition

A subsequence may skip positions, but it must keep their order. In Example 1, keeping 3 blocks both later values, while skipping it lets us keep [1, 2]. Enumerating picks and skips discovers this length, but many branches ask the same future question. For a given length, a smaller final value is always at least as easy to extend: ending at 1 instead of 3 preserves the chance to use a later 2. The fast method remembers only that smallest tail for each possible length, rather than every subsequence.

Approaches

Recursive Pick Or Skip

Solution Details

Reveal Recursive Pick Or Skip: intuition, complexity, and code

Hints

Hint 1
Fix the end first: the best run ending at each position extends the best compatible run before it.
Hint 2
For the faster method, track per length the smallest tail any run of that length can end with.
Hint 3
Tails stay sorted, so each value extends the runs or binary-searches the first tail at or above it and lowers that tail.

Edge Cases

  • All equal values like [7, 7, 7] return 1 since rises must be strict.
  • A fully descending array returns 1; every value only replaces the length-1 tail.
  • A fully ascending array extends on every value and returns n.
  • A minimum-bound value such as [-10000] still starts a length-1 subsequence; no previous index is different from a previous value of zero.
  • For [2, 3, 1], final tails is [1, 3], but 1 occurs after 3 and cannot precede it in a subsequence. The returned length 2 is correct via [2, 3]; the stored entries need not form a witness.

Common Mistakes and Interview Tips

  • Using >= instead of > when extending lets equal values chain and overcounts runs like [2, 2].
  • Returning the tails contents as the run itself; only its length is guaranteed, not its members.
  • Binary-searching for the value instead of its lower bound replaces the wrong tail on duplicates.
  • Sorting nums destroys original order: [3, 2, 1] has LIS length 1 even though its sorted values have length 3.
  • Searching all allocated Java tails slots reads unused zeros; restrict right to size - 1.
  • Presenting uncached recursion as viable for 2500 elements overlooks both exponential work and call-stack limits. In an interview, explain this limitation before choosing the fast method.

Key Takeaway

When subsequence length only cares about the best tail per length, maintain those tails in sorted order and place each element with binary search for a near-linear solution.