Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Merging two triplets replaces them with their component-wise max, so values only ever grow. The brute force tries subsets and merges them in exponential time. The greedy observation: any triplet with a component greater than the corresponding target value is poison — using it overshoots that axis forever. So keep only the 'safe' triplets (every component ≤ target), and check that for each of the three axes some safe triplet already equals the target there. If all three axes are hit, return true. One pass, O(n) time, O(1) space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you reason about the monotonicity of the merge (max only increases) to conclude that overshooting triplets are unusable, and whether you then decompose a seemingly-coupled 3D problem into three independent per-axis coverage checks.
Where candidates slip
Trying to enumerate which subset of triplets to merge (exponential), or forgetting to filter out triplets that exceed the target on some axis and then merging them — which silently overshoots and corrupts the result.
How to stand out
State the monotonicity argument explicitly — 'merge is component-wise max, so a too-big component can never come back down, hence any triplet exceeding target is poison' — then prove both directions: every usable triplet is safe, and merging all safe triplets reproduces target exactly when each axis is covered.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewCan merges produce target = [x,y,z]?How to choose what to merge?Try every subsetOptimalExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Brute Force — Enumerate Subsets and Merge
1Hint 1Explore hintHide hint
Since merge order doesn't matter, the result of merging a chosen set is just the component-wise max over that set. So the question is: does some subset have component-wise max equal to target?
2Hint 2Explore hintHide hint
The literal approach enumerates every subset, computes its component-wise max, and checks against target.
3Hint 3Explore hintHide hint
That's 2ⁿ subsets — astronomically too slow for n up to 10⁵. The point of writing it is to expose the structure that makes it collapsible.
A · Core idea
Because merging is associative and commutative max, merging any chosen set of triplets yields exactly the component-wise maximum of that set. So 'can we obtain target?' is equivalent to 'does some subset of triplets have a component-wise max equal to [x, y, z]?'. The brute force answers that literally: enumerate every subset, fold it with max, and compare to target.
Why subsets and not sequences. A first instinct is to model the sequence of merge operations, but order is irrelevant — max(max(a, b), c) = max(a, max(b, c)). Collapsing sequences to sets removes a huge amount of redundant exploration, but it still leaves 2ⁿ subsets to try.
Why this is hopeless at scale. With n up to 10⁵, 2ⁿ is beyond cosmic. Even at n = 30 it's a billion subsets. We're not going to run this; we write it to see the structure: each subset is judged purely by, for each axis independently, the maximum value it contributes on that axis.
Why the structure begs for a greedy. Notice the three axes are evaluated independently under max — the x-coordinate of the merged result depends only on the x-coordinates of the chosen triplets, never on their y or z. That independence is the crack we pry open: instead of choosing a subset jointly, we can reason axis-by-axis about which triplets are even allowed to participate. The next approach turns that into an O(n) test.
Why we keep the equivalence. The subset framing is what justifies the greedy's correctness later: when we prove 'target is achievable iff each axis is covered by a safe triplet', we're really characterising exactly which subsets have component-wise max equal to target.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
triplets = [[2,5,3],[1,7,5]], target = [2,7,5]{[2,5,3]}
max = [2,5,3]
≠ targettrueC · Code with teaching comments
Reference implementation previewpublic boolean mergeTriplets(int[][] triplets, int[] target) { int n = triplets.length; for (int mask = 1; mask < (1 << n); mask++) { int a = 0, b = 0, c = 0; for (int i = 0; i < n; i++) {Explore the full codeHide the full code
D · Why it works and complexityO(2ⁿ · n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Two reductions shrink the problem: merges → sets (order doesn't matter under max), and then sets → per-axis coverage (max evaluates each coordinate independently). The exponential brute force exists only to surface those two facts; once you see them, no enumeration is needed.
ComplexityO(2ⁿ · n) time, O(n) space — There are 2ⁿ subsets; computing the component-wise max of a subset costs up to O(n). The product O(2ⁿ · n) is exponential and infeasible beyond tiny n.
E · Edge cases and pitfalls3Modelling merge sequences instead of subsets — explodes the search even further for no reason.Explore edge casesHide edge cases
Pitfalls
- Modelling merge sequences instead of subsets — explodes the search even further for no reason.
- Believing 2ⁿ could pass — it can't beyond ~n=20; this is illustrative only.
- Including a triplet that overshoots target and still expecting a match — the merged max will exceed target.
Approach 2 of 2 · Optimal
Greedy — Filter Overshooters, Cover Each Axis (Optimal)
1Hint 1Explore hintHide hint
Merging takes a max, so values only ever go up. If a triplet has a component larger than target's, including it overshoots that axis — and you can never bring it back down. What does that say about which triplets are usable?
2Hint 2Explore hintHide hint
Keep only 'safe' triplets: those with all three components ≤ target. Merging any collection of safe triplets can never exceed target on any axis.
3Hint 3Explore hintHide hint
Among safe triplets, you need each axis to actually reach the target value. Track three booleans: does some safe triplet equal target on x? on y? on z? Return true iff all three are covered.
A · Core idea
Scan the triplets once. Call a triplet safe if a ≤ x and b ≤ y and c ≤ z — every component is within target. For each safe triplet, mark the axes on which it equals the target (a == x marks axis 0, and so on). After the pass, return true iff all three axes were marked.
Why overshooting triplets are poison — the monotonicity argument. Merging is component-wise max, so once any component exceeds its target value, no further merge can reduce it — max never decreases. Therefore if you ever fold a triplet with, say, a > x into your working set, the x-component is stuck above x forever and you can never equal target. So any triplet exceeding target on any axis is permanently unusable and must be discarded. Only safe triplets can participate.
Why it's free to merge all safe triplets — and why that proves sufficiency. Suppose for each axis there's a safe triplet equalling target there. Merge all safe triplets together. On axis x, the result is the max of a over all safe triplets; since every safe triplet has a ≤ x, that max is ≤ x, and since some safe triplet has a == x, the max is exactly x. The identical argument gives y on axis 2 and z on axis 3. So the merged triplet is exactly [x, y, z] — target is achievable. Crucially, throwing extra safe triplets into the merge can never hurt: they're all bounded by target, so they can't push any axis past it. That's why greed (take every safe triplet) is risk-free.
Why the condition is also necessary — the contradiction argument. Suppose target is achievable but some axis, say x, is not covered by any safe triplet. The achieving subset's component-wise max must equal x on that axis, so some triplet in the subset has a == x. For the subset to produce target, every triplet in it must be safe (an overshooter would have pushed some axis past target, as argued). So that triplet is a safe triplet with a == x — contradicting 'no safe triplet covers x'. Hence every axis covered by the achieving solution is covered by a safe triplet, and our three booleans capture exactly that. Both directions together make the three-way coverage check an exact characterisation, not a heuristic.
Why the axes can be treated independently. Component-wise max evaluates each coordinate in isolation — the x-result depends only on x-values. So 'cover x', 'cover y', 'cover z' are three independent sub-questions, and a single triplet may help with several at once. That independence is what lets one linear pass with three flags replace the exponential subset search.
Why this beats the brute force. The brute force searches 2ⁿ subsets; the greedy uses monotonicity to forbid overshooters and coordinate-independence to split into three trivial coverage checks, collapsing O(2ⁿ·n) to O(n) and O(n) space to O(1).
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
triplets = [[2,5,3],[1,8,4],[1,7,5]], target = [2,7,5]Interactive diagram
Why overshooters are poison
[2,5,3]Merge is component-wise max, so a component above target can never come back down — such triplets are filtered before any coverage check.
trueC · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The whole problem hinges on one property: the combine operation (max) is monotone, so anything that overshoots the target can only ever stay overshot — it's strictly harmful and gets filtered. Once the poison is gone, the remaining triplets can all be merged with impunity, and a multi-dimensional target decomposes into independent per-coordinate coverage. Spotting 'monotone combine ⇒ drop overshooters' is the transferable trick.
ComplexityO(n) time, O(1) space — One pass over n triplets with O(1) work each (three comparisons to test safety, three to update coverage) gives O(n) time; we keep three booleans, so O(1) space.
E · Edge cases and pitfalls6triplets = [[1,1,1]], target = [1,1,1] — Single safe triplet equals target on all three axes → hit = [T,T,T] → true.Explore edge casesHide edge cases
Edge cases handled
triplets = [[1,1,1]], target = [1,1,1]Single safe triplet equals target on all three axes → hit = [T,T,T] → true.triplets = [[3,4,5],[4,5,6]], target = [3,2,5]Both overshoot (b=4>2, b=5>2) so no safe triplet exists; y-axis (2) never covered → false.triplets = [[1,3,4],[2,5,8]], target = [2,5,8][1,3,4] safe but matches no axis; [2,5,8] safe and equals target on all axes → true.
Pitfalls
- Forgetting the safety filter and merging overshooting triplets — silently exceeds target on some axis.
- Requiring a single triplet to equal target on all axes instead of covering axes across several safe triplets.
- Returning true as soon as one axis is hit — all three must be covered.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic boolean mergeTriplets(int[][] triplets, int[] target) { boolean[] hit = new boolean[3]; for (int[] t : triplets) { if (t[0] <= target[0] && t[1] <= target[1] && t[2] <= target[2]) { for (int k = 0; k < 3; k++) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Skipping the overshoot filter
If you fold in a triplet with a component above target, the component-wise max permanently exceeds target on that axis — yet a naive coverage check might still report success.
Explore the code comparisonHide the code comparison
Skipping the overshoot filter
If you fold in a triplet with a component above target, the component-wise max permanently exceeds target on that axis — yet a naive coverage check might still report success.
Don't write this
hit = [False, False, False]
for t in triplets:
for k in range(3):
if t[k] == target[k]: # no safety check!
hit[k] = True
return all(hit)Write this instead
hit = [False, False, False]
for t in triplets:
if t[0] <= target[0] and t[1] <= target[1] and t[2] <= target[2]:
for k in range(3):
if t[k] == target[k]:
hit[k] = True
return all(hit)2Demanding a single all-axis match
Target can be assembled from several safe triplets, each contributing one or more axes. Requiring one triplet to equal target everywhere rejects valid inputs.
Explore the code comparisonHide the code comparison
Demanding a single all-axis match
Target can be assembled from several safe triplets, each contributing one or more axes. Requiring one triplet to equal target everywhere rejects valid inputs.
Don't write this
for (int[] t : triplets) {
if (t[0] == target[0] && t[1] == target[1] && t[2] == target[2])
return true; // misses multi-triplet builds
}
return false;Write this instead
boolean[] hit = new boolean[3];
for (int[] t : triplets) {
if (t[0] <= target[0] && t[1] <= target[1] && t[2] <= target[2])
for (int k = 0; k < 3; k++) if (t[k] == target[k]) hit[k] = true;
}
return hit[0] && hit[1] && hit[2];3Returning on the first axis covered
Coverage of one axis says nothing about the other two. The answer is the conjunction of all three coverage flags, checked after the full pass.
Explore the code comparisonHide the code comparison
Returning on the first axis covered
Coverage of one axis says nothing about the other two. The answer is the conjunction of all three coverage flags, checked after the full pass.
Don't write this
for t in triplets:
if t[0] <= target[0] and t[1] <= target[1] and t[2] <= target[2]:
if t[0] == target[0]:
return True # only checked axis xWrite this instead
# accumulate all three flags across the whole pass
return all(hit)Revise
Carry the pattern into the interview
Pattern to remember
Greedy filter-then-cover — discard overshooters, hit each axis
Code pattern to memorize
hit = [False, False, False]
for a, b, c in triplets:
if a <= tx and b <= ty and c <= tz: # safe triplet
if a == tx: hit[0] = True
if b == ty: hit[1] = True
if c == tz: hit[2] = True
return all(hit)Rules to remember
- 1Merging is component-wise max, so a value can only increase — you can never bring an overshot axis back down.
- 2A triplet with any component
> targetis unusable: include it and that axis overshoots permanently. Filter it out. - 3Among the safe triplets (all three components
≤ target), you need each axiskto be exactly equalled by some safe triplet. - 4It's always safe to merge every safe triplet — none can push an axis past target, so greediness costs nothing.
- 5Track three booleans (or a set) for 'axis x/y/z reached'; return true iff all three are hit.
- 6No need to actually merge or build subsets — the question reduces to three independent coverage checks.
Use this pattern when
- Combine operation is monotone (max/OR/union) so values only grow
- A target must be matched component-wise across independent axes
- Elements that exceed the target on any axis are strictly harmful and can be dropped
- You can decompose 'can we build X' into per-coordinate coverage checks
Choose another pattern when
- The combine operation can decrease a value (min, subtraction) → filtering logic flips or breaks
- Axes are coupled (a choice helping one axis forces another past target) → can't treat coordinates independently
- You must return the actual subset used → track contributors, not just booleans
- Targets aren't a fixed point of the operation → reframe the problem
Interview takeaway
Merge Triplets is the cleanest 'monotone combine + filter the poison' greedy: because max only grows, any triplet exceeding the target is forbidden, and once you keep only safe ones you can merge them all freely — the problem collapses to three independent 'did any safe triplet equal the target here?' checks. The same 'drop anything that can only overshoot' idea recurs wherever the combine operation is monotone.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternCanonical 'monotone combine + filter the poison' greedy: because merging is component-wise max (values only grow), any triplet exceeding the target on any axis is permanently unusable and is discarded, after which a multi-axis target decomposes into independent per-coordinate coverage checks. Recognise it whenever the combine operation is monotone and a target must be matched coordinate-by-coordinate.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Check if All the Integers in a Range Are CoveredComing soonCoverage thinking on a 1D range — mark covered points, verify full coverage.
- Path CrossingComing soonTrack visited coordinates in a set — sibling 'coverage via membership' check.
- Partition LabelsComing soonGreedy that tracks the max reach of each label — same 'monotone boundary' flavour.
- Maximum Performance of a TeamComing soonGreedy over a monotone dimension (efficiency) with a heap — pick what can only help.