Compute longest increasing subsequence
Company: TikTok
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates understanding of sequence algorithms, dynamic programming concepts, and algorithmic optimization for the longest increasing subsequence problem, including subsequence reconstruction and complexity analysis.
Constraints
- 0 <= n <= 10^5 (designed for large n so the O(n log n) method is justified)
- Values fit in a 32-bit signed integer and may be negative
- Duplicates may appear; the LIS must be STRICTLY increasing
- Returning any one valid LIS is acceptable when several exist
Examples
Input: ([10, 9, 2, 5, 3, 7, 101, 18],)
Expected Output: (4, [2, 3, 7, 101])
Explanation: LIS length is 4; [2,3,7,101] is one valid longest strictly increasing subsequence (so is [2,3,7,18]).
Input: ([],)
Expected Output: (0, [])
Explanation: Empty array: length 0 and an empty subsequence.
Hints
- Start with the O(n^2) DP: dp[i] = length of the longest strictly increasing subsequence ending at index i. Then ask what is redundant about rescanning all earlier elements.
- Maintain an array tails where tails[k] is the smallest possible tail value of any strictly increasing subsequence of length k+1. It stays strictly increasing, so you can binary-search it; len(tails) is the LIS length.
- For a STRICT LIS use bisect_left (leftmost tail >= x): overwrite that slot, or append if x exceeds every tail. (For the non-decreasing variant you'd switch to bisect_right.)
- tails is not itself a valid subsequence. To reconstruct, also record a predecessor pointer per index (the index occupying tails[pos-1] at write time) and backtrack from the index that achieved the maximum length.