—
i
Every number's bit count equals the bit count of its right-shifted half plus the lowest bit — a one-liner DP recurrence dp[i] = dp[i>>1] + (i&1) fills the entire answer array in a single O(n) pass.
Given a non-negative integer n, return an array dp of length n+1 where dp[i] is the number of 1-bits in i. For n = 5: 0,1,2,3,4,5 in binary are 0,1,10,11,100,101, so the answer is [0,1,1,2,1,2].
i right by one (i >> 1) drops the lowest bit. The result is a smaller index you've already computed. Add back that dropped bit (i & 1) and you have the full count: dp[i] = dp[i >> 1] + (i & 1). Every answer costs O(1) and depends on a previously-filled cell.dp[0] = 0 — zero has no set bits.i from 1 to n: dp[i] = dp[i >> 1] + (i & 1). Right-shifting halves the index (already filled); the low bit tells us if that last bit was a 1.dp is complete. No second pass needed.i & (i - 1) (Brian Kernighan — clears the lowest set bit) which also works: dp[i] = dp[i & (i - 1)] + 1. Both recurrences are O(n) overall, but i >> 1 is slightly cleaner because it only uses ordinary array indexing; the Kernighan form looks cleverer but is harder to read at a glance. Know both; default to the shift.dp[i] = dp[i >> 1] + (i & 1) (shift) and dp[i] = dp[i & (i - 1)] + 1 (Kernighan) both reduce to previously-known values in O(1). The shift form is the idiomatic choice for this problem.
n & (n-1) === 0), Sum of Two Integers (bit-level addition), and any DP where the transition discards one element of the representation.dp[0..5] where dp[i] = number of 1-bits in i. Base case: dp[0] = 0.function countBits(n: number): number[] {
const dp: number[] = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
dp[i] = dp[i >> 1] + (i & 1);
}
return dp;
}(n+1) array pre-filled with 0 gives us the base case dp[0] = 0 for free and avoids separate bounds checks.i from 1 to n: i >> 1 is the index of the same number with its lowest bit removed — always less than i, so already computed. i & 1 is 1 when the lowest bit is set, 0 otherwise. Summing them gives the full popcount.n & (n - 1)clears the lowest set bit; loop until zero, counting iterations. That's O(k) for k set bits.i takes O(log i) operations; summing log 1 + log 2 + … + log n ≈ n log n.dp[i] = dp[i & (i - 1)] + 1 — Brian Kernighan: each step clears the lowest set bit, which is a previously-computed index.n = 0 → [0]. The loop body never executes and the pre-filled array is the answer.| "return array of bit counts for 0..n" | DP with dp[i>>1] + (i&1) |
| popcount of every number up to n | one-pass DP, reuse smaller index |
| i & 1 — check lowest bit | isolate LSB, value is 0 or 1 |
| i >> 1 — drop lowest bit | parent index in the DP table |
const dp: number[] = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
dp[i] = dp[i >> 1] + (i & 1);
}
return dp;dp[i]?dp[6] when n = 6?i >> 1 always a valid (already-filled) index?dp[i] = dp[i & (i - 1)] + 1 is based on:countBits(0) return?n = 5, the full output is [0,1,1,2,1,2]. Which value is wrong in [0,1,1,2,2,2]?