One index can summarize a whole remaining choice
Picture
Pick values from a row, but never pick adjacent positions. Standing at index i, you can skip it or take it and jump past its neighbor. The future depends on where you resume. You do not need to carry the entire sequence of previous choices.
Predict
For [4, 5, 4], does taking the largest value first produce the best valid total?
Reveal the reasoning
No. Taking 5 excludes both 4s. Taking the two endpoints gives 8. The future effects of a local choice matter, so compare the complete consequences of taking and skipping.
Go deeper: derive the recurrence from disjoint first decisions
Let best(i) be the maximum total from positions i onward, with no earlier choice restricting position i. Picking nothing is allowed.
If you skip, the answer is best(i+1). If you take, it is values[i] + best(i+2). Every valid choice falls into one of these cases, so:
best(i) = max(best(i+1), values[i] + best(i+2)).
from functools import cache
def best_non_adjacent(values):
@cache
def best(i):
if i >= len(values):
return 0
return max(best(i + 1), values[i] + best(i + 2))
return best(0)
assert best_non_adjacent([4, 5, 4]) == 8
assert best_non_adjacent([-5, -1]) == 0
assert best_non_adjacent([]) == 0
The single independent coordinate is i. There are O(n) states, each with two choices, yielding O(n) time and O(n) cache/stack space. A reverse-index table evaluates the same recurrence.
Why no previous_was_taken flag? Taking position i jumps directly to i+2, where no earlier selection restricts the current position. The contract and transition have already encoded that restriction. A different formulation that advances one step every time may need a flag.
Analogy limit: “1D” does not mean “easy,” nor does it mean there is only one valid formulation. It describes the chosen state, not a property stamped permanently on the problem.
Change one rule
The positions form a circle, so the first and last positions are adjacent. Is the recurrence unchanged for the whole array?
Check the variation
No. For length at least two, solve two linear cases: exclude the first position, or exclude the last, and take the better result. Handle the empty and single-position inputs separately. Every valid circular choice excludes at least one endpoint.
Connect
Try the 5–10 line recurrence in the Python workshop. Tree DP changes adjacency from a row to a branching structure. LIS keeps one coordinate but scans many predecessors.