</> MAANG.io
coding interview ยท 101

Foundations

Master coding interviews with comprehensive coverage of data structures, algorithms, and problem-solving techniques. Progress from fundamentals to advanced topics with expertly curated content.

0/255 solved 0% complete

Opposite Direction Pointers

What is this?

Picture two people walking toward each other from opposite ends of a hallway. At every step you look at the pair where they stand and decide which person should take the next step inward. Because one marker always advances and they never turn back, the gap between them closes steadily until they meet, letting you solve the problem in a single sweep instead of comparing every pair.

flowchart TD A["Start L at left end and R at right end"] --> B["Evaluate the current pair"] B --> C["Decide which end is spent"] C --> D["Move that pointer inward"] D --> E["Stop when L and R meet"]

๐Ÿ’ก Fun fact: This is exactly how the classic "Container With Most Water" puzzle is solved. Always moving the shorter wall inward guarantees you never miss the best answer, even though you skip looking at most of the possible pairs.

๐Ÿ”“ The 3 problems in this chapter are free. Sign in with Google or Microsoft to start solving.


Core idea: Put one pointer at each end of the array and walk them toward each other. At every step you ask "which end is spent โ€” which one can I retire knowing I've lost nothing?" โ€” advance that one. The window shrinks by one each step, so the whole scan is O(n) with O(1) space.


The shape of the pattern

Array with left pointer L and right pointer R walking inward; the span between them is the window

Unlike a nested loop that re-examines pairs, opposite-direction pointers discard a candidate permanently on every move. The entire correctness argument lives in one sentence: why is it safe to advance this pointer instead of the other? Nail that discard rule and the code is four lines.


When to reach for it

  • The array is sorted, or the answer depends on both ends (extremes).
  • You're optimizing a quantity defined by a pair (max area, closest sum, a merged ordering).
  • You can argue that moving one end can never improve the result, so it's safe to drop.

If the input isn't ordered but the strategy needs order (greedy from both ends), sort first โ€” that's the O(n log n) setup behind problems like Bag of Tokens.


The three problems in this chapter

Flowchart: opposite-end pointers branch into Container With Most Water, Squares of a Sorted Array, and Bag of Tokens

Container With Most Water โ€” the discard rule, in its purest form

Two walls hold water up to the shorter of them, over the width between them. Start wide (L=0, R=n-1) and always move the shorter wall inward: the strong side is never the constraint, so retiring the weak side is the only move that can find something better.
โ†’ area = min(h[L], h[R]) ร— (R โˆ’ L); O(n) / O(1).

Squares of a Sorted Array โ€” the extremes hold the biggest values

After squaring a sorted (possibly negative) array, the largest squares sit at the two ends (most-negative vs most-positive). Compare the two ends, drop the bigger square into the result from the back, and step that end inward. A merge of two sorted runs without a sort.
โ†’ O(n) / O(n) (output array).

Bag of Tokens โ€” sort, then play both ends

Sort the tokens. Buy a point with the cheapest token (left) when you can afford it; when stuck, sell a point by cashing in the priciest token (right) to refuel power. Track the high-water score.
โ†’ O(n log n) to sort, then an O(n) two-pointer sweep.


The cross-cutting skill: the discard argument

Problem What "spent" means Which pointer moves
Container With Most Water the shorter wall caps the area move the shorter wall
Squares of a Sorted Array the larger magnitude is the next-biggest square move the end with the bigger square
Bag of Tokens cheapest buys a point; priciest refuels power left to score, right to refuel

Every opposite-end solution is "evaluate the pair, then move the spent end." If you can't say why the moved end is spent, you don't yet have a correct solution โ€” you have a guess.


๐Ÿ““ Draw it yourself

  1. The inward walk. Draw a row of bars, L at the left, R at the right, arrows pointing inward, and write your discard rule above the picture. Re-draw it for each of the three problems โ€” the rule changes, the skeleton doesn't.
  2. Fill-from-the-back. For Squares, draw the input with L/R and a separate result row being filled right to left. Seeing the result grow backward is the whole trick.

Snap photos and embed them with the /host-diagrams skill.


Complexity at a glance

Problem Time Space
Container With Most Water O(n) O(1)
Squares of a Sorted Array O(n) O(n) output
Bag of Tokens O(n log n) O(1) extra

Key takeaways

  • Start at both ends, walk inward. The window shrinks by one each step โ†’ O(n), O(1).
  • The discard rule is everything. Decide which end is "spent" and prove moving it loses nothing.
  • Sortedness powers the pattern โ€” and when a greedy needs order, sorting first (O(n log n)) is a legitimate setup, not a failure.
  • Why interviewers like it: it exposes whether you can replace a nested loop with a justified linear sweep โ€” and whether you can argue correctness, not just code it.

Order: Container With Most Water โ†’ Squares of a Sorted Array โ†’ Bag of Tokens. The discard rule gets subtler each step.

Container With Most Water

Core idea: The water a pair of walls holds is capped by the shorter wall, so start wide and always retire the shorter wall โ€” that is the only move that can ever buy you a taller ceiling.

Problem, rephrased

Forget vertical lines on a graph for a moment. Picture a row of rooftop rainwater pillars standing along a flat roof, one per slot. Each pillar has a height. You get to lay one straight gutter pipe horizontally between exactly two pillars; the rain that pools between them is bounded by the lower of the two pillar caps (water spills over the shorter one) and stretches across the gap between them.

You want to pick the two pillars that pool the most water. Concretely:

volume(i, j) = min(height[i], height[j]) * (j - i)

where j - i is how many slots apart the pillars sit (the width) and min(...) is the water ceiling (the height).

Return the maximum volume achievable over all pairs.

Input height Output Winning pair (indices) Why
[1, 8, 6, 2, 5, 9] 25 (1, 5) min(8, 9) * (5 - 1) = 8 * 4
[4, 4] 4 (0, 1) min(4, 4) * (1 - 0) = 4 * 1
[6, 1, 1, 1, 1, 6] 30 (0, 5) min(6, 6) * (5 - 0) = 6 * 5
[3, 0, 0, 2, 0, 4] 15 (0, 5) min(3, 4) * (5 - 0) = 3 * 5

Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account โ€” no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.