You're given an array of positive integers arr and a target k. Return true if some subsequence of arr has elements that sum to exactly k, and false otherwise.
A subsequence is what's left after you delete zero or more elements from the array — for each element you either keep it or drop it, and the kept elements stay in their original order. Every element can be used at most once.
Since a sum doesn't care about order, the real question is: can you choose some subset of the elements whose total is exactly k?
reachable[0] starts as true.bits |= bits << num, lighting 64 totals per CPU instruction.Input: arr = [10, 1, 2, 7, 6, 1, 5], k = 8 Output: true Several picks work: [1, 7] sums to 8, and so does [2, 6].
Input: arr = [2, 3, 5, 7, 9], k = 100 Output: false Even taking every element only reaches 2 + 3 + 5 + 7 + 9 = 26.
- 1 <= arr.length <= 2000 - 1 <= arr[i] <= 1000 - 1 <= k <= 2000
This is the gateway problem of the subsequence pattern: one tiny take-it-or-leave-it decision per element, repeated n times, quietly generates every subsequence there is. Master the decision tree here, then watch the same skeleton solve the entire knapsack family.
In plain English: pick any subset of the array's elements (keep them or skip them, one decision each). Formally: return true if there exist indices i1 < i2 < … < im such that arr[i1] + arr[i2] + … + arr[im] = k.
Worked example 1 — arr = [10, 1, 2, 7, 6, 1, 5], k = 8
pick 1 and 7 → 1 + 7 = 8 ✓ pick 2 and 6 → 2 + 6 = 8 ✓ answer: true (one way is enough)
Worked example 2 — arr = [2, 3, 5, 7, 9], k = 100
even the whole array: 2 + 3 + 5 + 7 + 9 = 26 < 100 answer: false
Asking two or three sharp questions before coding shows an interviewer you design around guarantees instead of discovering them mid-bug.
“Are all elements positive, or can they be negative or zero?”
Everything here hinges on positivity: once a running total exceeds k it can never come back down, which unlocks pruning and bounds the DP table at k. Negatives break both.
“Can an element be used more than once?”
No — take-or-skip, once each. If reuse were allowed this becomes a different (unbounded) problem with a different loop direction.
“What if the array has a single element?”
The answer is simply whether that element equals k — a great sanity test for your base cases.
“Does the empty subsequence count as a valid pick?”
It sums to 0, and k is at least 1, so it can never be the answer — but sum 0 being reachable is the seed every solution grows from.
“How large can n and k get?”
Up to 2000 each. 2^n subsequences is unthinkable, but an n times k table is only about 4 million cells — that number is the whole strategy.
Before I code, I want to confirm a few guarantees.
Are all the elements positive? If so, a running total that overshoots k is dead and I can prune it.
Each element is usable at most once, correct?
And with n and k both up to 2000, I'm aiming for an n-times-k solution rather than enumerating subsequences.
Stand on each element once and make one binary choice. Two options per element, n elements — the decision tree's leaves are exactly the 2^n subsequences. Recursion walks this tree for free.
(i=0, need 8)
/ \
take 10 skip 10
(i=1, need -2) ✗ (i=1, need 8)
/ \
take 1 skip 1
(i=2, need 7) (i=2, need 8) …Two different paths that both arrive at index i still needing 7 have identical futures. The history of which elements produced that state is irrelevant. So the tree's 2^n paths collapse into at most n * (k + 1) distinct states (i, remaining) — solve each once, remember the answer.
Instead of chasing one target down a tree, keep a board of totals 0…k and light up every total you can build. Start with 0 lit (the empty pick). Each new number num lights s wherever s - num was already lit. Because all elements are positive, the board never needs a slot above k — anything bigger can never shrink back. The moment slot k lights up, the answer is true.
| Brute force | Memoization | Optimal | |
|---|---|---|---|
| Time | O(2^n) | O(n · k) | O(n · k) |
| Space | O(n) recursion | O(n · k) | O(k) |
The full, runnable code for each step of the arc lives in the Approaches selector below.
Key takeaway
Take-or-skip recursion enumerates every subsequence; noticing that only (index, remaining) matters collapses it into a table of reachable sums. That collapse is the subset-sum pattern — the seed of the entire knapsack family.
reachable = bool array of size k+1; reachable[0] = true
for each num in arr:
for s from k down to num:
if reachable[s - num]: reachable[s] = true
if reachable[k]: return true
return reachable[k]