Given a list of integers, write a function that returns the largest sum of non-adjacent numbers. Numbers can be
0
or negative.For example,
[2, 4, 6, 2, 5]
should return13
, since we pick2
,6
, and5
.[5, 1, 1, 5]
should return10
, since we pick5
and5
.Follow-up: Can you do this in O(N) time and constant space
How to think?
Always start from make few assumption / examples to see the parttens:
For example:
[5,1,1,5]
Start from i = 0: max sum can be Math.max(5, 0)
// memo: [5]
Then i = 1: max sum can be Math.max(memo[0], arr[1]), which is memo[1] = Math.max(5, 1) ---> 5
// memo :: [5, 5]
Then i = 2: max sum can be Math.max(memo[i - 1], arr[i] + memo[i - 2]), which is memo[2] = Math.max(5, 1 +5) --> 6:
// memo :: [5, 5, 6]
Then i = 3, should follow i = 2 partten:
// memo :: [5, 5, 6, 10]
So now, we got our partten:
for i = 2 to length memo[i] = Math.max(memo[i - 1], memo[i - 2] + arr[i])
Code:
function maxNonAdjSum(arr) { const memo = new Array(arr.length).fill(0); memo[0] = Math.max(0, arr[0]); memo[1] = Math.max(arr[1], memo[0]); for (let i = 2; i < arr.length; i++) { memo[i] = Math.max(memo[i-1], arr[i] + memo[i - 2]); } return memo; } console.log(maxNonAdjSum([2, 4, 6, 2, 5])); // 13 console.log(maxNonAdjSum([5, 1, 1, 5])); // 10 console.log(maxNonAdjSum([2, 4, 6, 2, 5, -3, 4, 0])); // 17
To improve it furuther for space, we don't really need to keep 'memo' as a whole array, we just need to remember 3 values:
// [max_inc, max_not_inc, max]
And:
max = Math.max(max + max_inc, max_not_inc)
Cdoe:
function maxNonAdjSum2(arr) { let max_inc = Math.max(0, arr[0]); let max_not_inc = Math.max(arr[1], max_inc); let max = max_inc for (let i = 2; i < arr.length; i++) { max = Math.max(arr[i] + max_inc, max_not_inc); max_inc = max_not_inc; max_not_inc = max; } return max; } console.log(maxNonAdjSum2([2, 4, 6, 2, 5])); // 13 console.log(maxNonAdjSum2([5, 1, 1, 5])); // 10 console.log(maxNonAdjSum2([2, 4, 6, 2, 5, -3, 4, 0])); // 17