Bird
Raised Fist0
Interview Prepdp-advanced-trees-bitmaskmediumAmazonGoogleMicrosoftOracle

Longest Increasing Subsequence

Choose your preparation mode4 modes available
▶
Steps
setup

Initialize tails array as empty

Start with an empty 'tails' array which will store the smallest tail values of increasing subsequences.

💡 This empty array is the foundation; it will grow as we process numbers and track subsequences.
Line:tails = []
💡 The algorithm begins with no subsequences, so tails is empty.
📊
Longest Increasing Subsequence - Watch the Algorithm Execute, Step by Step
Watching this step-by-step visualization helps you understand how the algorithm efficiently maintains subsequence tails to find the LIS length without enumerating all subsequences.
Step 1/10
·Active fill★Answer cell
Initializing dp array
i\w01234567
i=0????????
Item 0 - wt:0 val:10
i\w01234567
i=010???????
append 10
Item 1 - wt:0 val:9
i\w01234567
i=09???????
replace 10 with 9
Item 2 - wt:0 val:2
i\w01234567
i=02???????
replace 9 with 2
Item 3 - wt:0 val:5
i\w01234567
i=025??????
append 5
Item 4 - wt:0 val:3
i\w01234567
i=023??????
replace 5 with 3
Item 5 - wt:0 val:7
i\w01234567
i=0237?????
append 7
Item 6 - wt:0 val:101
i\w01234567
i=0237101????
append 101
Item 7 - wt:0 val:18
i\w01234567
i=023718????
replace 101 with 18
Item 7 - wt:0 val:18
i\w01234567
i=023718????
final tails

Key Takeaways

✓ The 'tails' array stores the smallest possible tail values for increasing subsequences of each length.

This insight is hard to see from code alone because the array is updated non-intuitively via replacements, not by storing actual subsequences.

✓ Binary search efficiently finds where to place each number in 'tails', enabling O(n log n) time complexity.

Visualizing each binary search step clarifies why the algorithm is faster than naive DP approaches.

✓ Replacing elements in 'tails' with smaller numbers keeps subsequences optimally extendable.

Seeing replacements step-by-step shows how the algorithm maintains flexibility for longer subsequences.

Practice

(1/5)
1. Given an integer array, you need to count all arithmetic subsequences of length ≥ 3. Which approach guarantees an optimal solution that efficiently counts subsequences by their common difference without enumerating all subsequences explicitly?
easy
A. Brute force enumeration of all subsequences and checking arithmetic property
B. Dynamic programming with hash maps storing counts of subsequences by difference
C. Greedy approach selecting longest arithmetic subsequence only
D. Sorting the array and using two pointers to find arithmetic triplets

Solution

  1. Step 1: Understand problem constraints

    Counting all arithmetic subsequences of length ≥ 3 requires tracking subsequences by their common difference, which brute force cannot do efficiently.
  2. Step 2: Identify approach that counts subsequences by difference

    DP with hash maps stores counts of subsequences ending at each index with a given difference, enabling O(n²) time complexity.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    DP with hash maps is the known optimal approach for this problem [OK]
Hint: Counting subsequences by difference requires DP with hash maps [OK]
Common Mistakes:
  • Thinking greedy or sorting solves counting all subsequences
  • Assuming brute force is feasible for large n
2. Consider the following iterative postorder traversal code snippet for computing the maximum path sum in a binary tree. Given the tree: 1 / \ 2 3 What is the final value of max_sum after the algorithm completes?
easy
A. 4
B. 6
C. 5
D. 3

Solution

  1. Step 1: Trace gains for leaf nodes

    Node 2 and Node 3 are leaves, so gains[2] = 2, gains[3] = 3, max_sum updated to max(-inf, 2) = 2, then max(2,3) = 3.
  2. Step 2: Compute gains for root node 1

    left_gain = max(gains[2],0) = 2, right_gain = max(gains[3],0) = 3, price_newpath = 1 + 2 + 3 = 6, max_sum updated to max(3,6) = 6.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Sum of path 2 -> 1 -> 3 is 6 [OK]
Hint: Sum path through root includes both children gains [OK]
Common Mistakes:
  • Forgetting to add both children
  • Using only max child gain
  • Off-by-one in stack processing
3. You are given a 2D grid of integers and need to find the length of the longest strictly increasing path moving only up, down, left, or right. Which algorithmic approach guarantees an optimal solution for this problem?
easy
A. Greedy approach that always moves to the neighbor with the largest value
B. Topological sort based dynamic programming processing cells in ascending order of their values
C. Simple DFS from each cell without memoization
D. Breadth-first search layer by layer from the smallest values

Solution

  1. Step 1: Understand problem constraints

    The problem requires finding the longest strictly increasing path in a matrix, which can be modeled as a directed graph where edges go from smaller to larger values.
  2. Step 2: Identify suitable algorithm

    Topological sort based DP processes nodes in ascending order, ensuring all dependencies are resolved before updating dp values, guaranteeing optimal substructure and avoiding recomputation.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Topological sort ensures correct order for DP updates [OK]
Hint: Longest increasing path -> topological sort DP [OK]
Common Mistakes:
  • Assuming greedy always works
  • Using DFS without memoization causing TLE
  • Using BFS layer by layer ignoring value order
4. The following code attempts to count the number of longest increasing subsequences using DP arrays. Identify the bug that causes incorrect counting of LIS.
medium
A. counts array is initialized with zeros instead of ones
B. lengths array should be initialized with zeros instead of ones
C. The condition nums[j] < nums[i] should be nums[j] <= nums[i]
D. The final sum should be over counts where lengths are less than max_len

Solution

  1. Step 1: Check initialization of counts array

    Counts represent number of LIS ending at each index; initially each element alone forms LIS of length 1, so counts[i] must start at 1, not 0.
  2. Step 2: Consequence of zero initialization

    With counts initialized to 0, counts[i] remains 0 unless updated, causing undercounting of LIS and incorrect final result.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Initialize counts with 1 to count single-element subsequences [OK]
Hint: Counts must start at 1 to count single elements [OK]
Common Mistakes:
  • Initializing counts with zeros
  • Using <= instead of <
  • Summing counts incorrectly
5. What is the time complexity of the bottom-up bitmask DP solution for the Travelling Salesman Problem with n cities, and why? Options:
medium
A. O(n * 2^n) because we process each subset and city once
B. O(2^n) because subsets dominate the complexity
C. O(n^2 * 2^n) because for each subset and city, we check all possible previous cities
D. O(n! ) because we consider all permutations of cities

Solution

  1. Step 1: Identify loops in the code

    There are three nested loops: over all subsets (2^n), over all cities (n), and over all possible previous cities (n).
  2. Step 2: Multiply loop complexities

    Total complexity is O(2^n * n * n) = O(n^2 * 2^n). O(n * 2^n) because we process each subset and city once misses the inner loop over previous cities, underestimating complexity.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Bitmask DP complexity is well-known as O(n^2 * 2^n) [OK]
Hint: Remember triple nested loops: subsets, current city, previous city [OK]
Common Mistakes:
  • Ignoring inner loop over previous cities leads to underestimation
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard