Compute longest increasing subsequence
Company: TikTok
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Overview: 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.
Read the full TikTok Machine Learning Engineer interview experience this question came from
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.