|
| 1 | +# Introduction |
| 2 | + |
| 3 | +There are a couple of approaches to solve Knapsack. |
| 4 | +You can recursively determine whether each item should be added to the knapsack. |
| 5 | +Or, you can solve it iteratively using a dynamic programming approach. |
| 6 | + |
| 7 | +## General guidance |
| 8 | + |
| 9 | +The key to solving Knapsack is to determine whether each item should be added to the knapsack or not. |
| 10 | +An item should be added only if: |
| 11 | + |
| 12 | +1. There is enough capacity to add the item and: |
| 13 | +2. It increases the total value. |
| 14 | + |
| 15 | +## Approach: Recursive |
| 16 | + |
| 17 | +```java |
| 18 | +import java.util.List; |
| 19 | + |
| 20 | +class Knapsack { |
| 21 | + |
| 22 | + int maximumValue(int maxWeight, List<Item> items) { |
| 23 | + if (items.isEmpty()) { |
| 24 | + return 0; |
| 25 | + } |
| 26 | + |
| 27 | + List<Item> remainingItems = items.subList(1, items.size()); |
| 28 | + int valueWithout = maximumValue(maxWeight, remainingItems); |
| 29 | + |
| 30 | + Item item = items.get(0); |
| 31 | + if (item.weight > maxWeight) { |
| 32 | + return valueWithout; |
| 33 | + } |
| 34 | + |
| 35 | + int valueWith = maximumValue(maxWeight - item.weight, remainingItems) + item.value; |
| 36 | + return Math.max(valueWithout, valueWith); |
| 37 | + } |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +For more information, check the [Recursive approach][approach-recursive]. |
| 42 | + |
| 43 | +## Approach: Dynamic programming |
| 44 | + |
| 45 | +```java |
| 46 | +import java.util.List; |
| 47 | + |
| 48 | +class Knapsack { |
| 49 | + |
| 50 | + int maximumValue(int maxWeight, List<Item> items) { |
| 51 | + int [][]maxValues = new int[maxWeight + 1][items.size() + 1]; |
| 52 | + |
| 53 | + for (int nItems = 0; nItems <= items.size(); nItems++) { |
| 54 | + maxValues[0][nItems] = 0; |
| 55 | + } |
| 56 | + |
| 57 | + for (int itemIndex = 0; itemIndex < items.size(); itemIndex++) { |
| 58 | + Item item = items.get(itemIndex); |
| 59 | + |
| 60 | + for (int capacity = 0; capacity <= maxWeight; capacity++) { |
| 61 | + if (capacity < item.weight) { |
| 62 | + maxValues[capacity][itemIndex + 1] = maxValues[capacity][itemIndex]; |
| 63 | + } else { |
| 64 | + int valueWith = maxValues[capacity - item.weight][itemIndex] + item.value; |
| 65 | + int valueWithout = maxValues[capacity][itemIndex]; |
| 66 | + maxValues[capacity][itemIndex + 1] = Math.max(valueWith, valueWithout); |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + return maxValues[maxWeight][items.size()]; |
| 72 | + } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +For more information, check the [dynamic programming approach][approach-dynamic]. |
| 77 | + |
| 78 | +## Which approach to use? |
| 79 | + |
| 80 | +The recursive approach is inefficient because it recalculates the maximum value for some item combinations a number of times. |
| 81 | +The dynamic programming approach avoids this by storing them in an [array][array]. |
| 82 | +In addition, the dynamic programming approach is also an iterative approach and avoids overhead of making method calls. |
| 83 | + |
| 84 | +[approach-recursive]: https://exercism.org/tracks/java/exercises/knapsack/approaches/recursive |
| 85 | +[approach-dynamic]: https://exercism.org/tracks/java/exercises/knapsack/approaches/dynamic-programming |
| 86 | +[array]: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html |
0 commit comments