From 7f0c9851fbdf1dd6ce2907f3f8c991a1044e193f Mon Sep 17 00:00:00 2001 From: jaebradley Date: Thu, 11 Jan 2018 22:15:37 -0500 Subject: [PATCH] implement maximum non adjacent element sum --- .../maximumNonAdjacentElementSumIdentifier.md | 70 +++++++++++++++++++ ...aximumNonAdjacentElementSumIdentifier.java | 31 ++++++++ ...umNonAdjacentElementSumIdentifierTest.java | 54 ++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 codereview/maximumNonAdjacentElementSumIdentifier.md create mode 100644 src/main/java/problems/impl/MaximumNonAdjacentElementSumIdentifier.java create mode 100644 src/test/java/problems/impl/MaximumNonAdjacentElementSumIdentifierTest.java diff --git a/codereview/maximumNonAdjacentElementSumIdentifier.md b/codereview/maximumNonAdjacentElementSumIdentifier.md new file mode 100644 index 0000000..b0b60ca --- /dev/null +++ b/codereview/maximumNonAdjacentElementSumIdentifier.md @@ -0,0 +1,70 @@ +## Purpose + +I recently came across an interview question that stumped me for a while +> Given a list of integers, write a function that returns the largest sum of non-adjacent numbers. + +I am looking for feedback around both my implementation and the correctness of my proposed solution (I have some test +cases, but I could have missed a case). + +## Approach + +For arrays with `1` or `2` values, the answer is trivial. + +For arrays with more than `2` values, keep track of the maximum sum from the preceding non-adjacent elements that +*includes the most recent non-adjacent element*, and the maximum sum from the preceding non-adjacent elements that +*excludes the most recent non-adjacent element*. + +So for `[3, 1, 1, 5, 1]` at index `3`, the maximum sum from preceding non-adjacent elements that includes the most recent +non-adjacent element is `1`, while the maximum sum from preceding non-adjacent elements that excludes the most recent +non-adjacent element is `3`. + +Taking the max of these two sums and adding them to the current value will produce the maximum sum for non-adjacent +elements up to that index. Continuing this process for each remaining index and then comparing the last two calculated +sums will produce the maximum sum. + +Let's walk through this process with `[3, 1, 1, 5, 1]`. + +* At index `0`, the max sum is `3` +* At index `1`, the max sum is `1` +* At index `2`, the max sum from including the most recent non-adjacent element is `3`, while the max sum from excluding + the most recent non-adjacent element is `0`. Thus, we choose `3` and add that to the current value (`1`). `4` is now + the max non-adjacent sum for index `2`. +* At index `3`, the max sum from including the most recent non-adjacent element is `1`, while the max sum from excluding + the most recent non-adjacent element is `3`. Thus, we choose `3` and add that to the current value (`5`). `8` is now + the max non-adjacent sum for index `3`. +* At index `4`, the max sum from including the most recent non-adjacent element is `4`, while the max sum from excluding + the most recent non-adjacent element is `3`. Thus, we choose `4` and add that to the current value (`1`). `6` is now + the max non-adjacent sum for index `4`. +* The final two sums were `8` and `6` - we take the max (`8`). + +Apologies if this was confusing to follow, it was difficult to describe my thought process. + +## Implementation + + + + public class MaximumNonAdjacentElementSumIdentifier { + public static int identify(int[] values) { + if (values == null || values.length == 0) { + throw new RuntimeException("Unable to identify sum"); + } + + if (values.length == 1) { + return values[0]; + } + + int firstSum = 0; + int secondSum = values[0]; + int previousValueSum = values[1]; + + for (int i = 2; i < values.length; i++) { + int value = values[i]; + int maximumCurrentElementSum = Math.max(firstSum, secondSum) + value; + firstSum = Math.max(firstSum, secondSum); + secondSum = previousValueSum; + previousValueSum = maximumCurrentElementSum; + } + + return Math.max(secondSum, previousValueSum); + } + } diff --git a/src/main/java/problems/impl/MaximumNonAdjacentElementSumIdentifier.java b/src/main/java/problems/impl/MaximumNonAdjacentElementSumIdentifier.java new file mode 100644 index 0000000..2133ed1 --- /dev/null +++ b/src/main/java/problems/impl/MaximumNonAdjacentElementSumIdentifier.java @@ -0,0 +1,31 @@ +package problems.impl; + +/** + * Given a list of integers, write a function that returns the largest sum of non-adjacent numbers. + */ + +public class MaximumNonAdjacentElementSumIdentifier { + public static int identify(int[] values) { + if (values == null || values.length == 0) { + throw new RuntimeException("Unable to identify sum"); + } + + if (values.length == 1) { + return values[0]; + } + + int firstSum = 0; + int secondSum = values[0]; + int previousValueSum = values[1]; + + for (int i = 2; i < values.length; i++) { + int value = values[i]; + int maximumCurrentElementSum = Math.max(firstSum, secondSum) + value; + firstSum = Math.max(firstSum, secondSum); + secondSum = previousValueSum; + previousValueSum = maximumCurrentElementSum; + } + + return Math.max(secondSum, previousValueSum); + } +} diff --git a/src/test/java/problems/impl/MaximumNonAdjacentElementSumIdentifierTest.java b/src/test/java/problems/impl/MaximumNonAdjacentElementSumIdentifierTest.java new file mode 100644 index 0000000..c485130 --- /dev/null +++ b/src/test/java/problems/impl/MaximumNonAdjacentElementSumIdentifierTest.java @@ -0,0 +1,54 @@ +package problems.impl; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MaximumNonAdjacentElementSumIdentifierTest { + @Test + public void itShouldIdentifySum1() { + int[] values = new int[] { 5, 1, 1, 7, 3}; + int expected = 12; + assertEquals(expected, MaximumNonAdjacentElementSumIdentifier.identify(values)); + } + + @Test + public void itShouldThrowAnExceptionForNullValues() { + try { + MaximumNonAdjacentElementSumIdentifier.identify(null); + } catch (RuntimeException e) { + // expected + } + } + + @Test + public void itShouldThrowAnExceptionForEmptyValues() { + try { + MaximumNonAdjacentElementSumIdentifier.identify(new int[] {}); + } catch (RuntimeException e) { + // expected + } + } + + @Test + public void itShouldReturnValueForSingleElementValues() { + int value = 5; + int[] values = new int[] { value }; + assertEquals(value, MaximumNonAdjacentElementSumIdentifier.identify(values)); + } + + @Test + public void itShouldReturnGreaterValueForTwoElementValues() { + assertEquals(5, MaximumNonAdjacentElementSumIdentifier.identify(new int[]{4, 5})); + } + + @Test + public void itShouldReturnGreatestSingleValueForThreeElementValues() { + assertEquals(3, MaximumNonAdjacentElementSumIdentifier.identify(new int[]{-1, 1, 3})); + } + + @Test + public void itShouldReturnGreatestCombinedValuesForThreeElementValues() { + assertEquals(8, MaximumNonAdjacentElementSumIdentifier.identify(new int[]{2, 7, 6})); + } +} \ No newline at end of file