—
rob2 (dp[i-2])
You can't rob two adjacent houses — so the choice at each house is: skip it and keep the previous best, or rob it and add to what you had two houses back. Two rolling variables replace the full DP array.
Given an array of non-negative integers nums where each element is the money in a house, return the maximum amount you can rob tonight without alerting the police — adjacent houses are connected and you cannot rob two houses in a row.
Example: nums = [2, 7, 9, 3, 1]. Rob houses 0, 2, 4 → 2 + 9 + 1 = 12. Any other non-adjacent selection yields less. Answer: 12.
i, you have exactly two choices: skip it (answer stays dp[i-1]) or rob it (answer becomes dp[i-2] + nums[i]). The adjacency constraint is the entire reason you look back two steps instead of one — robbing house imeans you couldn't have touched house i-1.dp[0] = nums[0] (only one house); dp[1] = max(nums[0], nums[1]) (pick the richer of the first two). In the rolling approach both start at 0 and the loop handles them naturally.dp[i] = max(dp[i-1], dp[i-2] + nums[i]). Why: either you skipped house i (best is whatever you had through i-1) or you robbed it (last safe house was i-2).rob2 (two back) and rob1 (one back). After computing best, shift: rob2 = rob1, rob1 = best.rob1 after the loop holds the global maximum.rob1 as rob2 before overwriting it. Many learners write rob1 = best; rob2 = rob1 — but by then rob1 is already the new value, so rob2 gets best instead of the old rob1. Always assign rob2 first.Both approaches are O(n) time. The rolling trick drops space from O(n) to O(1) because the recurrence only depends on i-1 and i-2.
5 housesin a row. Adjacent houses have alarms — you can't rob two in a row. Goal: maximize total loot.function rob(nums: number[]): number {
let rob2 = 0; // best loot up to two houses back (dp[i-2])
let rob1 = 0; // best loot up to one house back (dp[i-1])
for (const n of nums) {
const best = Math.max(rob1, rob2 + n); // skip vs rob
rob2 = rob1;
rob1 = best;
}
return rob1;
}rob2 represents the best loot through the house two positions back (dp[i-2]) and rob1 represents the best through one position back (dp[i-1]). Both start at 0 so the first iteration works without a special base-case branch.Math.max(rob1, rob2 + n) encodes the two choices: skip this house (answer stays rob1) or rob it (add n to rob2, the last safe state). The adjacency constraint forces us to reach back to rob2— if we robbed the previous house we can't use it.rob2 = rob1 then rob1 = best. Order is critical — rob2 must be updated before rob1, otherwise rob2 gets the new best instead of the old one-step-back value.rob1 holds the maximum loot across the whole array. For [2, 7, 9, 3, 1] the answer is 12.dp[i-1] and dp[i-2].nums[0..n-2] and once on nums[1..n-1], and take the max.dp[] array and backtrack: if dp[i] === dp[i-1] you skipped house i, otherwise you robbed it (jump to i-2).Math.max will simply skip any house with a negative value since not robbing it (rob1) will always be better.dp[i] = max(dp[i-1], dp[i-k-1] + nums[i]), and you'd need to keep a window of k+1 previous values instead of just two.| "can't take two adjacent elements" | dp[i] = max(dp[i-1], dp[i-2] + val) |
| maximize sum, non-adjacent picks | House Robber rolling DP |
| 1-D DP referencing only last 2 rows | roll to O(1) space with rob1/rob2 |
| "circular array, same constraint" | House Robber II — run twice, exclude ends |
function rob(nums: number[]): number {
let rob2 = 0; // dp[i-2]
let rob1 = 0; // dp[i-1]
for (const n of nums) {
const best = Math.max(rob1, rob2 + n);
rob2 = rob1;
rob1 = best;
}
return rob1;
}nums = [2, 7, 9, 3, 1], what is the answer?rob1 = best; rob2 = rob1; — what goes wrong?nums = [1, 2, 3, 1], what does the algorithm return?