Skip to main content
Two Pointers Pattern

Pattern Recognition Cheatsheet (Read This First)

Reach for Two Pointers when the problem statement says…Hard signal: the array is sorted (or you can sort), AND you need to find pairs / triplets / partitions, AND you want O(1) extra space. That is the Two Pointers calling card. If sorting is forbidden or destroys the answer, use HashMap instead.

What is Two Pointers?

The Two Pointers pattern uses two pointers to traverse an array or string, typically moving towards each other or in the same direction. It transforms O(n squared) brute force solutions into O(n) optimal ones.
Quick Recognition: If you see a sorted array + need to find pairs/triplets + want O(1) space, Two Pointers is likely the answer.

Canonical Template Code

This is the boilerplate. Memorize it. Then specialize for the problem.

Pattern Recognition Checklist

Before using Two Pointers, ask yourself:

Use Two Pointers When

  • Array is sorted (or can be sorted)
  • Need to find pairs with a property
  • In-place modification required
  • Need to compare elements from ends
  • Want to avoid O(n²) nested loops

Don't Use When

  • Need to preserve original order
  • Array is unsorted and sorting changes answer
  • Need to find subarrays (use Sliding Window)
  • Need lookup by value (use HashMap)

When to Use

Sorted Arrays

Finding pairs, triplets, or elements with specific sum

Palindrome Problems

Checking or creating palindromes

Merging Arrays

Merging sorted arrays or linked lists

Removing Duplicates

In-place array modifications

Pattern Variations

1. Opposite Direction (Converging)

Pointers start at both ends and move towards the center.

2. Same Direction (Fast & Slow)

Both pointers move in the same direction at different speeds.

3. Container With Most Water

4. Valid Palindrome

5. 3Sum

6. Trapping Rain Water

7. Move Zeroes

8. Sort Colors (Dutch National Flag)

Classic Problems

Problem: Find two numbers in a sorted array that add up to target.Approach: Use converging pointers. If sum is too small, move left pointer right. If too large, move right pointer left.Time: O(n) | Space: O(1)
Problem: Find two lines that form a container holding the most water.Approach: Start from both ends. Move the pointer with the shorter line inward (greedy choice).Time: O(n) | Space: O(1)
Problem: Check if a string is a palindrome (ignoring non-alphanumeric).Approach: Compare characters from both ends, skip non-alphanumeric.Time: O(n) | Space: O(1)
Problem: Find all unique triplets that sum to zero.Approach: Sort array, fix one element, use two pointers for remaining two.Time: O(n^2) | Space: O(1) excluding output
Problem: Calculate trapped water between elevation bars.Approach: Two pointers with max height tracking from both sides.Time: O(n) | Space: O(1)

Template Code

Common Mistakes

Avoid These Pitfalls:
  1. Off-by-one errors: Be careful with left < right vs left <= right
  2. Infinite loops: Ensure pointers always move towards termination
  3. Missing edge cases: Empty arrays, single elements, all duplicates
  4. Modifying while iterating: Be careful when removing elements in-place

Debugging Checklist

When your Two Pointers solution fails, check:
1

Initialization

Are left and right starting at correct positions?
2

Loop Condition

Should it be left < right or left <= right?
3

Pointer Movement

Is at least one pointer moving in each iteration?
4

Edge Cases

Did you handle empty array, single element, all same elements?
5

Duplicates

Are you skipping duplicates correctly (for unique results)?

Complexity Quick Reference

Interview Problems by Company

Interview Tips

Script for interviews:
  1. “I notice the array is sorted, which suggests Two Pointers might work here.”
  2. “I’ll use two pointers starting at opposite ends.”
  3. “If the sum is too small, I move left pointer right to increase it.”
  4. “If too large, I move right pointer left to decrease it.”
  5. “This gives us O(n) time and O(1) space.”
Be ready for these follow-ups:
  • “What if there are duplicates?” → Skip duplicates in loop
  • “What if no solution exists?” → Return appropriate default
  • “Can you handle negative numbers?” → Usually yes, same logic
  • “What if array is not sorted?” → Sort first, or use HashMap

Practice Problems

Practice Roadmap

1

Day 1: Basics

  • Solve: Two Sum II, Valid Palindrome
  • Focus: Understanding when to move which pointer
2

Day 2: Fast-Slow

  • Solve: Move Zeroes, Remove Duplicates
  • Focus: In-place modifications
3

Day 3: Multi-pointer

  • Solve: 3Sum, Sort Colors
  • Focus: Managing multiple pointers
4

Day 4: Advanced

  • Solve: Container With Water, Trapping Rain Water
  • Focus: Greedy decisions with pointers
Interview Tip: When you see a sorted array or need to find pairs/triplets, immediately consider Two Pointers before jumping to HashMap.

Worked LeetCode Problems

Five canonical problems. For each: signal that triggers Two Pointers, brute force first, optimized solution, and the bugs that fail edge cases.

LC 167 — Two Sum II (Input Array Is Sorted)

Problem. Given a 1-indexed sorted array of integers and a target, return the indices of two numbers that add up to the target. Exactly one solution exists. Pattern fit. “Sorted array” + “two numbers summing to target” — the textbook Two Pointers signal. Brute force. Two nested loops, O(n squared) time, O(1) space. Even though the array is sorted, brute force ignores that signal. Optimized with Two Pointers.
Why it works. Each step eliminates one row or column of the implicit pair matrix. We never miss the answer because moving inward on the wrong side would only worsen the sum direction. Complexity. O(n) time, O(1) space. Common bugs.
  • Forgetting 1-indexed return. LC 167 wants 1-indexed indices. Off-by-one fails 100% of test cases.
  • Using left <= right. Allows using the same element twice. Returns wrong pair when target == 2 * arr[i].

LC 15 — 3Sum

Problem. Given an integer array, find all unique triplets that sum to zero. Pattern fit. “All triplets summing to X” — fix one element, run Two Pointers on the rest. Brute force. Three nested loops, O(n cubed). Use a set of sorted tuples to dedupe — messy. Optimized.
Complexity. O(n squared) time (sort dominated by inner scan), O(1) extra space ignoring output. Common bugs.
  • Skipping duplicates after recording, but only on one side. You must skip on both left and right, otherwise [-2, 0, 0, 2, 2] produces [[-2, 0, 2], [-2, 0, 2]].
  • Forgetting to break when nums[i] > 0. Not a correctness bug, but a 5x performance loss on large inputs with many positives.

LC 11 — Container With Most Water

Problem. Given an array of heights, find two lines that together with the x-axis form a container holding the most water. Pattern fit. “Pair from sorted-by-position array” + “maximize area” — greedy converging Two Pointers. Brute force. All pairs, O(n squared). Optimized.
Why moving the shorter side is correct. The area is bounded by the shorter line. Moving the taller side cannot increase the area (height is still bounded by the shorter side, and width decreases). Moving the shorter side at least gives a chance to find a taller pair. Complexity. O(n) time, O(1) space. Common bugs.
  • Moving the taller side. Misses the optimum on inputs like [1, 8, 6, 2, 5, 4, 8, 3, 7].
  • Updating area after moving pointers. Then you skip the current pair’s contribution. Always update before moving.

LC 125 — Valid Palindrome

Problem. Return true if string is a palindrome considering only alphanumeric characters and ignoring case. Pattern fit. “Palindrome check” — converging Two Pointers from both ends. Brute force. Build a filtered, lowercased string and compare with its reverse. O(n) time, O(n) space. Optimized.
Complexity. O(n) time, O(1) space. Common bugs.
  • Forgetting left < right inside the inner skip loops. Causes index out-of-range when the entire string is non-alphanumeric, e.g., "....," or "...." (returning true is correct).
  • Comparing characters without .lower(). Fails on "A man, a plan, a canal: Panama".

LC 42 — Trapping Rain Water

Problem. Given an array of bar heights, compute the total water trapped after rain. Pattern fit. “Compute aggregate over array using boundaries from both sides” — converging Two Pointers with running maxes. Brute force. For each index, find max to left and max to right, take min, subtract bar height. O(n squared). Better but still not optimal. Precompute left-max and right-max arrays. O(n) time, O(n) space. Optimized (Two Pointers).
Why it works. When height[left] < height[right], we know the right side has at least one bar taller than left_max somewhere to the right. So water at left is determined purely by left_max (the right bound is already known to be at least as tall). Process the bottleneck side first. Complexity. O(n) time, O(1) space. Common bugs.
  • Initializing left_max = height[0] then accidentally double-counting position 0. Initialize to 0 and let the first comparison update it.
  • Comparing left_max against right_max instead of height[left] against height[right]. The decision is which current bar is shorter, not which max.

Caveats and Traps — Two Pointers
  • Using left <= right when you should use left < right. The <= allows the same index for both pointers, which means using one element twice. Catastrophic for sum problems where target = 2 * arr[i]. Use <= only when single-element processing is meaningful (Dutch flag, binary search variants).
  • Not sorting before applying converging pointers. Two Pointers requires monotonic order to make meaningful comparisons. On unsorted input, the pointer movement logic breaks because moving “right” on an unsorted array does not predictably increase or decrease anything.
  • Skipping duplicates only on one side in 3Sum. You must skip duplicate nums[left] AND duplicate nums[right] after recording a triplet. Otherwise [0, 0, 0, 0] outputs [0, 0, 0] multiple times.
  • Forgetting to update the result before moving pointers. In Container With Most Water, if you move pointers first and then update area, you miss the contribution of the current pair.
  • Using sort + Two Pointers on a problem that requires original indices. LC 1 (Two Sum, unsorted) wants original indices. Sorting destroys them unless you store (value, original_index) pairs. Use HashMap instead.
  • Confusing fast/slow with converging variants. Fast/slow rewrites in-place (LC 26, 283). Converging searches for pairs (LC 167, 15). They have different invariants — pick deliberately.
  • Off-by-one on the reverse merge (LC 88). Place pointers at m - 1, n - 1, m + n - 1. Forgetting to copy remaining nums2 elements after p1 finishes is the most common bug.
  • Trapping Rain Water with the wrong comparison. Compare height[left] to height[right], not left_max to right_max. The current-bar comparison is what tells you which side is the bottleneck.
Solutions and Patterns — Two Pointers Idioms
  • Always sort first unless the problem says “preserve order” or “indices required.” Sorting is O(n log n), often dominated by the O(n) or O(n squared) main scan — effectively free.
  • Use < for converging, <= for fast/slow inclusive scans. The mental check: “When left == right, is there meaningful work left?” If no, use <.
  • Skip duplicates by checking against the previous element. if i > 0 and nums[i] == nums[i-1]: continue is the canonical idiom in 3Sum / 4Sum.
  • For “fix-and-converge” patterns, wrap the converging two-pointer scan in an outer loop that fixes the first 1, 2, or k-2 elements. This generalizes 2Sum to kSum naturally.
  • For in-place modifications, the slow pointer always points to the next write position (not the current valid element). After the loop, slow is the new length.
  • For trapping rain water and similar, process the bottleneck side first. The side with the smaller current height is the binding constraint; you can compute its contribution without knowing the other side’s exact future.
  • For palindrome checks, wrap inner skip loops with while left < right and .... Otherwise inner loops can run past each other on degenerate inputs.
  • For merging from the end (LC 88), write from the back to avoid overwriting unread data. After the main loop, only nums2 leftovers need to be copied — nums1 leftovers are already in place.

Curated LeetCode Practice List

Group your practice by difficulty. Solve every Easy, then move to Medium. Hard problems are useful only after Easy and Medium feel mechanical.

Easy (start here, 5-8 problems)

Medium (the meat of interview prep, 6-8 problems)

Hard (after you have grinded the above, 5-6 problems)

Interview Questions

Deep-dive questions that test real understanding of the Two Pointers pattern, not just pattern matching. Expect interviewers to push past your initial answer.
Difficulty: SeniorWhat interviewers are really testing: Whether you understand the greedy correctness proof behind the pointer movement, not just that it works. This separates candidates who memorize solutions from those who can reason about algorithmic correctness and would be able to derive similar greedy strategies for novel problems.Strong answer:
  • The area is min(height[left], height[right]) * (right - left). When we move a pointer inward, the width always decreases by 1. The only way to get a larger area is if the height increases enough to compensate.
  • Suppose height[left] < height[right]. If we moved right inward instead, the new height is still capped by height[left] (since min(anything, height[left]) <= height[left]), AND the width decreased. So area strictly decreases or stays the same. We can safely discard all pairs involving current left with any right' < right.
  • This is essentially an elimination argument: by moving the shorter side, we only eliminate pairs that provably cannot beat the current best. We never skip a pair that could be optimal.
  • Complexity: O(n) time, O(1) space. Each pointer moves at most n times total.
Red flag answer: “You move the shorter one because a taller line might give more water.” This is hand-waving. If a candidate cannot articulate why no optimal pair is skipped, they memorized the pattern without understanding it. Another red flag: saying “it’s like binary search” — it is not, and that analogy breaks down immediately.Follow-ups:
  1. What if there are many lines with the same height? Does the algorithm degenerate? What is the worst-case number of comparisons? (Answer: still O(n), each pointer moves at most n/2 times regardless of duplicates.)
  2. Can you modify this to return ALL pairs of lines whose area is within 10% of the maximum? Does the two-pointer approach still work, or do you need a different strategy? (Answer: two-pointer no longer works cleanly because the elimination argument breaks — you would need to explore more pairs, potentially O(n^2) in the worst case, or use a sorted/stack-based approach.)
Difficulty: Foundational (but the trap is the real test)What interviewers are really testing: Whether you blindly apply two pointers to every “find a pair” problem, or whether you recognize when a HashMap is the better tool. This is a pattern-recognition trap — strong candidates explain the trade-off; weak candidates force two pointers.Strong answer:
  • For an unsorted array, the right answer is a HashMap/HashSet, not two pointers. Insert each element and check if target - current exists. O(n) time, O(n) space.
  • Two pointers requires sorting first, which is O(n log n) and also destroys original indices — if the problem asks for indices (like LeetCode Two Sum), you lose that information unless you store original indices separately.
  • The trade-off: HashMap gives O(n) time but O(n) space. Sorting + two pointers gives O(n log n) time but O(1) space (if you do not need indices). Choose based on constraints.
  • In an interview, I would state: “Since the array is unsorted and we need O(n) time, I will use a HashMap. If the interviewer constrains me to O(1) space and does not need original indices, I would sort then use two pointers.”
Red flag answer: Immediately jumping to “sort the array and use two pointers” without considering that sorting is O(n log n) and destroys index information. Or even worse: not knowing that two pointers requires a sorted input at all.Follow-ups:
  1. What if memory is extremely constrained (embedded system, 2MB RAM) but the array has 100 million elements on disk? Now sorting + two pointers (external sort) might beat the HashMap approach. Walk me through that trade-off.
  2. What if there are many duplicate values? Does the HashMap approach need modification? (Answer: depends on whether you need all pairs or just one. For all pairs, you need to store counts or lists of indices.)
Difficulty: IntermediateWhat interviewers are really testing: Whether you understand that sorting is not an arbitrary choice but a structural prerequisite that enables both the two-pointer scan and duplicate elimination. Also tests whether you can reason about alternatives and their costs.Strong answer:
  • Sorting serves two critical purposes in 3Sum:
    1. Enables two-pointer scanning: After fixing one element, the remaining subarray is sorted, so converging pointers can systematically search in O(n) instead of O(n^2).
    2. Makes duplicate skipping trivial: In a sorted array, duplicates are adjacent. You just check if nums[i] == nums[i-1]: continue. Without sorting, you would need a HashSet to track which triplets you have already seen, which is messier and uses O(k) extra space for k results.
  • Without sorting, you would need a HashMap-based approach: for each pair (i, j), check if -(nums[i] + nums[j]) exists. This is O(n^2) time (same as sorted approach) but requires O(n) extra space for the map and a set of sorted tuples to deduplicate results, which is error-prone.
  • The sorting cost is O(n log n), and the two-pointer scan is O(n^2), so sorting does not change the overall O(n^2) complexity. It is essentially “free.”
Red flag answer: “We sort because two pointers needs a sorted array” without explaining WHY two pointers needs sorted input or mentioning the duplicate-skipping benefit. Another red flag: not realizing the sorting cost is dominated by the O(n^2) scan.Follow-ups:
  1. If the problem changes to 4Sum, how does the complexity change? Can you still use two pointers? (Answer: yes, fix two elements O(n^2), two-pointer scan O(n) for each = O(n^3) total. The pattern generalizes: k-Sum is O(n^(k-1)) with sorting + two pointers.)
  2. What if the array is already sorted and has 10 million elements? What practical optimizations would you add? (Answer: early termination — if nums[i] > 0, no triplet starting here can sum to zero. If nums[i] + nums[i+1] + nums[i+2] > 0, break. These prune aggressively.)
Difficulty: FoundationalWhat interviewers are really testing: Attention to off-by-one errors, which are the #1 source of bugs in pointer-based code. This also reveals whether a candidate tests their code mentally with small inputs or just writes and hopes.Strong answer:
  • left < right means the pointers must have at least one element between them or be adjacent. When left == right, the loop exits. Use this when you are comparing/processing pairs of distinct elements (e.g., Two Sum, palindrome check, Container With Most Water).
  • left <= right means even when both pointers point to the same element, you still process it. Use this when a single element might still need processing (e.g., Dutch National Flag / Sort Colors, binary search).
  • Concrete bug example: In the palindrome check, using left <= right would not cause a bug (checking a single middle character against itself is fine), but in Two Sum, using left <= right could cause you to use the same element twice — returning [i, i] as a valid pair when arr[i] * 2 == target.
  • The mental model I use: Ask yourself: “When left == right, is there still meaningful work to do, or have I already considered everything?” If the answer is no, use <. If yes, use <=.
Red flag answer: “I always use left < right for two pointers.” This shows the candidate does not think about why, just memorizes. Another red flag: being unable to produce a concrete input where the wrong condition causes a failure.Follow-ups:
  1. In binary search, when do you use left < right vs left <= right vs left + 1 < right? What bug does each variant prevent? (Tests whether the candidate connects two-pointer reasoning to binary search, which is fundamentally a two-pointer technique.)
  2. Walk me through what happens with the input [1, 2, 3, 4, 5] and target 6 using Two Sum with left <= right. Where exactly does it break? (Answer: when left = right = 2, it would return [2, 2] claiming 3 + 3 = 6, but you cannot use the same element twice.)
Difficulty: SeniorWhat interviewers are really testing: Deep understanding of a Hard-level problem with multiple valid approaches. The interviewer wants to see if you can explain the invariant that makes the two-pointer version work, and whether you have the judgment to discuss trade-offs between approaches.Strong answer:
  • Core invariant: At any position, the water trapped equals min(max_left, max_right) - height[i]. The two-pointer approach works because we always process from the side with the smaller known maximum. If left_max < right_max, we know the water at left is determined by left_max regardless of what lies between the pointers (since right_max is already larger, and anything in between could only increase the right maximum further).
  • Why it is correct: We process the “bottleneck side” first. When left_max < right_max, the constraining factor at position left is left_max, not right_max. So we can safely compute water at left without knowing the exact right_max — we just know it is at least as large.
  • Three approaches compared:
  • My interview strategy: I would start by explaining the prefix/suffix approach (simpler, harder to get wrong), then optimize to two pointers if asked for O(1) space.
Red flag answer: Jumping straight to the two-pointer solution without being able to explain the invariant. If a candidate says “we track the max from both sides and add the difference” but cannot explain WHY processing the smaller-max side first is valid, they memorized the code. Also a red flag: not knowing the prefix array approach exists.Follow-ups:
  1. What if this is a 2D grid instead of 1D bars (LC 407 — Trapping Rain Water II)? Does two-pointer generalize? (Answer: no. You need a priority queue / BFS approach processing the boundary inward. The 1D invariant does not extend to 2D because water can escape in multiple directions.)
  2. If the input is a stream of heights arriving one at a time and you need a running total of trapped water, which approach adapts best? (Answer: the monotonic stack approach adapts most naturally to streaming, since it processes left-to-right. Two pointers requires the full array upfront.)
Difficulty: Intermediate (pattern misidentification trap)What interviewers are really testing: Whether the candidate distinguishes between two pointers and sliding window — they are related but not identical. This problem is sliding window, not classic two pointers. Candidates who lump them together reveal shallow pattern understanding.Strong answer:
  • This is a sliding window problem, not a classic two-pointer problem. The distinction matters:
    • Two pointers typically work on sorted data or compare elements at both ends. Pointer movement is driven by comparison logic (sum too big/small, palindrome match/mismatch).
    • Sliding window maintains a window with an invariant (in this case, “no repeating characters”) and expands/shrinks to maintain it. Pointer movement is driven by window validity.
  • The approach: expand the right pointer to grow the window. When a duplicate is found, shrink from the left until the window is valid again. Use a HashSet or HashMap to track characters in the current window.
  • Complexity: O(n) time (each character is added and removed from the set at most once), O(min(n, alphabet_size)) space.
Red flag answer: “I would use two pointers starting from both ends” — this is completely wrong for this problem since you need to scan left-to-right maintaining a window. Another red flag: calling it “two pointers” without distinguishing the sliding window invariant. If a candidate cannot explain why converging pointers would fail here, they do not understand either pattern deeply enough.Follow-ups:
  1. What if instead of “no repeating characters” the constraint is “at most K distinct characters”? How does your approach change? (Answer: same sliding window, but the HashMap tracks character counts. Shrink when distinct count exceeds K.)
  2. Can you solve this with O(1) space if the input is guaranteed to be lowercase English letters only? (Answer: yes, use a fixed-size array of 26 instead of a HashMap. Space is O(1) since it does not grow with input size.)
Difficulty: IntermediateWhat interviewers are really testing: Whether the candidate can adapt a known template to a modified constraint, rather than only solving the exact problem they memorized. This is LC 80 (Remove Duplicates II) and tests flexible thinking with the fast-slow pattern.Strong answer:
  • The standard remove-duplicates uses slow to track the write position and skips when arr[fast] == arr[slow]. For “at most twice,” we need to compare arr[fast] against arr[slow - 1] (two positions back) instead of arr[slow].
  • Key insight: If arr[fast] == arr[slow - 1], we already have two copies of this value, so skip. Otherwise, write it.
  • Generalization: For “at most K duplicates,” compare arr[fast] against arr[slow - (K-1)]. This is a clean generalization that interviewers love.
  • Complexity: O(n) time, O(1) space. Single pass.
Red flag answer: Using a counter variable to track how many times the current element has appeared. While this works, it is more complex and error-prone than the slow - 2 comparison trick. An even worse red flag: not realizing the array must be sorted for this approach to work, or wanting to use extra space.Follow-ups:
  1. What if the array is not sorted? Can you still remove elements appearing more than twice in O(n) time? (Answer: you need a HashMap to count frequencies, then a second pass to filter. O(n) time but O(n) space. Two pointers alone cannot solve this on unsorted input.)
  2. The interviewer says: “Now do it where each element appears at most K times, and K is a parameter.” Write it generalized. (Answer: shown above. Tests whether the candidate can abstract a pattern into a parameter.)
Difficulty: SeniorWhat interviewers are really testing: Whether the candidate can extend the two-pointer pattern to higher dimensions (4Sum), reason about time complexity of nested approaches, and apply pruning optimizations that show real problem-solving maturity.Strong answer:
  • Approach: Sort the array. Use two nested loops to fix the first two elements. For the remaining two, use converging two pointers. This gives O(n^3) time.
  • Duplicate handling: Skip duplicates at each level — for the first loop, second loop, and within the two-pointer scan. Same logic as 3Sum but applied at more levels.
  • Critical pruning optimizations (what separates good from great):
    1. Early termination (too small): If nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target, break the outer loop — all remaining sums are larger.
    2. Early termination (too large): If nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target, skip this i — even the largest possible sum with this i is too small.
    3. Same pruning applies at the second loop level.
  • Complexity: O(n^3) time worst case, O(1) space (excluding output). With pruning, practical performance is much better.
  • Why not HashMap? You could use a HashMap of pair sums for O(n^2) time, but handling duplicates becomes extremely messy and the space is O(n^2). For an interview, the sorted + nested two-pointer approach is cleaner and safer to implement.
Red flag answer: Not being able to articulate the time complexity (saying O(n^2) because “two pointers is O(n)”). The correct reasoning: two outer loops O(n^2) times the two-pointer scan O(n) = O(n^3). Another red flag: implementing it without any pruning, then being unable to suggest optimizations when prompted.Follow-ups:
  1. What is the general time complexity for K-Sum using this approach? (Answer: O(n^(K-1)). You nest K-2 loops and use two pointers for the innermost pair.)
  2. For very large arrays where O(n^3) is too slow, can you think of a meet-in-the-middle approach? What is its complexity? (Answer: compute all pair sums in O(n^2), sort them, then use two pointers on the pair-sum array to find complementary pairs. Time is O(n^2 log n), but duplicate handling and reconstructing original indices is tricky.)
Difficulty: SeniorWhat interviewers are really testing: Whether the candidate can apply two pointers in a non-obvious setting. This is not the classic sorted-array two-pointer usage — it requires finding boundaries from both ends using a monotonicity invariant. Tests creative application of the pattern beyond textbook scenarios.Strong answer:
  • Approach: Use two pointers, but not the classic converging pair. Scan from the left to find the rightmost element that is “out of order” (smaller than some element to its left). Scan from the right to find the leftmost element that is “out of order” (larger than some element to its right).
  • Detailed steps:
    1. Traverse left to right, tracking the running maximum. Whenever nums[i] < max_so_far, this position needs to be inside the sorted subarray. Track the rightmost such position as right_bound.
    2. Traverse right to left, tracking the running minimum. Whenever nums[i] > min_so_far, this position needs to be inside the sorted subarray. Track the leftmost such position as left_bound.
    3. The answer is right_bound - left_bound + 1. If no such bounds exist, the array is already sorted (return 0).
  • Why this works: Any element that violates the monotonicity when scanning from either end MUST be included in the subarray that needs sorting.
  • Complexity: O(n) time, O(1) space. Two passes.
Red flag answer: “Sort the array and compare with the original to find the first and last mismatched positions.” While this gives the correct answer, it is O(n log n) time and O(n) space. If a candidate cannot improve beyond this, they do not understand how to use pointer-based scanning. Another red flag: trying to use converging two pointers from both ends simultaneously, which does not work here because the “out of place” boundaries are not symmetric.Follow-ups:
  1. Can you prove that sorting just this subarray is sufficient? What if an element outside the subarray is affected? (Answer: by construction, all elements left of left_bound are smaller than everything in the subarray and already sorted, and all elements right of right_bound are larger and already sorted. So sorting the subarray restores global order.)
  2. How would you adapt this if the requirement changes to “find the shortest subarray to REVERSE (not sort) to make the array sorted”? (Answer: much harder. The subarray to reverse must form a decreasing sequence that, when flipped, creates a valid sorted array. This requires checking that the reversed subarray merges correctly with both ends.)
Difficulty: Foundational (but the insight is the real test)What interviewers are really testing: Whether the candidate recognizes that starting from the end (reverse two-pointer) avoids overwriting elements that have not been processed yet. This is LC 88 (Merge Sorted Array) and is a classic interview warm-up that reveals whether a candidate truly understands pointer mechanics or just memorizes forward-scanning patterns.Strong answer:
  • The key insight: If you merge from the front, you overwrite elements in nums1 that you still need. By merging from the back (placing the largest elements first), you fill the trailing empty space and never overwrite unprocessed elements.
  • Use three pointers: p1 at the last real element of nums1, p2 at the last element of nums2, and write at the very end of nums1. Compare nums1[p1] and nums2[p2], place the larger one at write, and decrement.
  • Edge case: If p2 finishes first, nums1’s remaining elements are already in place. If p1 finishes first, copy the rest of nums2. The second case is the one most candidates forget.
  • Complexity: O(m + n) time, O(1) space. Truly in-place.
Red flag answer: “Create a temporary array, merge into it, copy back.” This works but uses O(m + n) space and shows the candidate did not consider the reverse-direction insight. Also a red flag: writing the forward merge and not realizing it overwrites needed data until the interviewer points it out.Follow-ups:
  1. Why do we not need to handle the case where p1 still has elements remaining? (Answer: those elements are already in their correct positions in nums1. Since we are writing from the back and nums1 is sorted, any remaining nums1 elements are the smallest and are already at the front.)
  2. What if instead of two sorted arrays, you had K sorted arrays and needed to merge them all? Does the two-pointer approach scale, or do you need a fundamentally different technique? (Answer: for K arrays, use a min-heap / priority queue of size K. Two pointers does not generalize to K-way merge efficiently — pairwise merging would be O(nK) vs O(n log K) with a heap.)