Solve increasing sequence and path problems
Company: Meta
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: Solve increasing sequence and path problems evaluates algorithm design, data structures, correctness, complexity, edge cases, and implementation details in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Longest Strictly Increasing Contiguous Subarray
Constraints
- 0 <= len(nums) <= 10^5
- -10^9 <= nums[i] <= 10^9
- Strictly increasing means nums[i] > nums[i-1] (equal values break the run)
- Return [0, -1, -1] for an empty array
- On ties, return the leftmost (smallest start index) subarray
Examples
Input: ([1, 2, 1, 2, 3],)
Expected Output: [3, 2, 4]
Explanation: The run [1,2,3] at indices 2..4 has length 3, the longest strictly increasing run.
Input: ([],)
Expected Output: [0, -1, -1]
Explanation: Empty array returns the sentinel [0, -1, -1].
Input: ([5],)
Expected Output: [1, 0, 0]
Explanation: A single element is a run of length 1 at index 0.
Input: ([5, 4, 3, 2, 1],)
Expected Output: [1, 0, 0]
Explanation: Strictly decreasing: every run has length 1; leftmost is index 0.
Input: ([1, 2, 3, 4, 5],)
Expected Output: [5, 0, 4]
Explanation: The whole array is one strictly increasing run.
Input: ([1, 2, 3, 1, 2, 3, 4],)
Expected Output: [4, 3, 6]
Explanation: Two runs of length 3 then 4; the run [1,2,3,4] at indices 3..6 is longest.
Input: ([3, 3, 3],)
Expected Output: [1, 0, 0]
Explanation: Equal values are not strictly increasing, so the longest run is length 1, leftmost at index 0.
Input: ([-5, -4, -3, 0, 2],)
Expected Output: [5, 0, 4]
Explanation: Negatives are handled normally; the entire array is strictly increasing.
Hints
- Track the start index of the current increasing run. Whenever nums[i] <= nums[i-1], the run breaks and a new run starts at i.
- Keep a running best (length, start, end). Update it only when the current run is STRICTLY longer than the best so far — this naturally keeps the leftmost answer on ties.
- A single linear pass with a handful of integer variables gives O(n) time and O(1) space.
Longest Strictly Increasing Subsequence (with Reconstruction)
Constraints
- 0 <= len(nums) <= 2500
- -10^9 <= nums[i] <= 10^9
- Strictly increasing: each chosen element must be greater than the previous chosen element
- Return [0, []] for an empty array
- Use bisect_left (lower bound) so that duplicates do NOT extend the subsequence
Examples
Input: ([10, 9, 2, 5, 3, 7, 101, 18],)
Expected Output: [4, [2, 3, 7, 18]]
Explanation: LIS length is 4; patience sorting reconstructs [2, 3, 7, 18].
Input: ([],)
Expected Output: [0, []]
Explanation: Empty array has no subsequence.
Input: ([7],)
Expected Output: [1, [7]]
Explanation: A single element forms an LIS of length 1.
Input: ([0, 1, 0, 3, 2, 3],)
Expected Output: [4, [0, 1, 2, 3]]
Explanation: Length 4; one valid LIS reconstructed by the algorithm is [0, 1, 2, 3].
Input: ([7, 7, 7, 7, 7, 7, 7],)
Expected Output: [1, [7]]
Explanation: Equal values cannot extend a strictly increasing subsequence, so LIS length is 1.
Input: ([5, 4, 3, 2, 1],)
Expected Output: [1, [1]]
Explanation: Strictly decreasing input: the longest strictly increasing subsequence is any single element; this canonical procedure yields [1].
Input: ([1, 2, 3, 4, 5],)
Expected Output: [5, [1, 2, 3, 4, 5]]
Explanation: Already sorted ascending: the whole array is the LIS.
Input: ([-2, -1, 0, -3, 5],)
Expected Output: [4, [-2, -1, 0, 5]]
Explanation: Negatives handled normally; [-2, -1, 0, 5] is a length-4 LIS.
Hints
- Maintain a 'tails' array where tails_vals[k] is the smallest possible tail value of any strictly increasing subsequence of length k+1. Its length equals the LIS length.
- For each value x, binary-search (bisect_left) its position. If it lands at the end, the LIS grew; otherwise it replaces an existing tail, keeping tails minimal for future extension.
- To reconstruct, store a parent pointer for each index pointing to the element at the previous tail slot, then walk back from the last element that extended the longest tail and reverse.
Longest Increasing Path in a Matrix (LeetCode 329)
Constraints
- 1 <= m, n <= 500 (return 0 for an empty grid)
- 0 <= matrix[i][j] <= 2^31 - 1
- Moves are only to the four orthogonal neighbors and only to strictly larger values
- Equal-valued neighbors do not extend a path
Examples
Input: ([[9, 9, 4], [6, 6, 8], [2, 1, 1]],)
Expected Output: 4
Explanation: Path 1 -> 2 -> 6 -> 9 has length 4.
Input: ([[3, 4, 5], [3, 2, 6], [2, 2, 1]],)
Expected Output: 4
Explanation: Path 3 -> 4 -> 5 -> 6 has length 4.
Input: ([[1]],)
Expected Output: 1
Explanation: A single cell is a path of length 1.
Input: ([],)
Expected Output: 0
Explanation: Empty grid returns 0.
Input: ([[7, 7], [7, 7]],)
Expected Output: 1
Explanation: All values equal; no strictly increasing move exists, so the longest path is 1.
Input: ([[1, 2, 3, 4, 5]],)
Expected Output: 5
Explanation: A single row strictly increasing left to right has a path of length 5.
Input: ([[5], [4], [3], [2], [1]],)
Expected Output: 5
Explanation: A single column; moving up from bottom 1 -> 2 -> 3 -> 4 -> 5 is length 5.
Input: ([[1, 2], [4, 3]],)
Expected Output: 4
Explanation: Path 1 -> 2 -> 3 -> 4 spiraling through all four cells has length 4.
Hints
- Define f(r, c) = length of the longest strictly increasing path that STARTS at cell (r, c). The answer is the max of f over all cells.
- f(r, c) = 1 + max(f(neighbor)) over neighbors with a strictly greater value (or 1 if none). Memoize f(r, c) so each cell is computed once.
- Because you only ever move to strictly larger values, the recursion graph is a DAG — no explicit visited set is needed and there is no risk of cycles.