Skip to content

Commit 4dc0d12

Browse files
authored
Add easier hint and example solution for Knapsack exercise (#1650)
* Replace example solution with something simpler * Add hint on simple brute-force approach [no important files changed]
1 parent 8925745 commit 4dc0d12

File tree

2 files changed

+21
-23
lines changed

2 files changed

+21
-23
lines changed

exercises/practice/knapsack/.docs/hints.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
## General
44

5-
- A good starting point is a brute-force recursive solution.
6-
You can see it sketched out in the first half of the article ["Demystifying the 0-1 knapsack problem: top solutions explained"](demystifying-the-knapsack-problem).
7-
- For a more efficient solution, you can improve your recursive solution using _dynamic programming_, which is introduced in the second half of [the above-mentioned article](demystifying-the-knapsack-problem).
8-
For a more general explainer, see the video ["5 Simple Steps for Solving Dynamic Programming Problems"](solving-dynamic-programming-problems)
9-
- If you need a more visual walkthrough of how to apply dynamic programming to the knapsack problem, see the video ["0/1 Knapsack problem | Dynamic Programming"](0-1-knapsack-problem).
10-
Also worth mentioning is [this answer](intuition-of-dp-for-knapsack-problem) to a question on Reddit, _"What is the intuition behind Knapsack problem solution using dynamic programming?"_.
11-
Below is the answer in full.
5+
- If you're not sure where to start, try a brute-force solution:
6+
- First, generate all possible combinations of items. [`Array#combination`](https://rubyapi.org/3.3/o/array#method-i-combination) might come in handy.
7+
- Then, find the combination that has the highest value and is within the weight limit.
8+
- If you want to make your solution as efficient as possible, look into an algorithmic technique called _dynamic programming_. Here are some resources:
9+
- ["Demystifying the 0-1 knapsack problem: top solutions explained"](demystifying-the-knapsack-problem).
10+
- ["5 Simple Steps for Solving Dynamic Programming Problems"](solving-dynamic-programming-problems)
11+
- ["0/1 Knapsack problem | Dynamic Programming"](0-1-knapsack-problem).
12+
- [This answer](intuition-of-dp-for-knapsack-problem) to a question on Reddit, _"What is the intuition behind Knapsack problem solution using dynamic programming?"_. Below is the answer in full.
1213

1314
> The intuition behind the solution is basically like any dynamic programming solution: split the task into many sub-tasks, and save solutions to these sub-tasks for later use.
1415
>
Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
# This solution uses dynamic programming to memoize solutions to overlapping
2-
# subproblems, so that they don't need to be recomputed. It's essentially a
3-
# recursive solution that remembers best-so-far outputs of previous inputs. The
4-
# algorithm has a time complexity of O(n * W), where n is the number of items
5-
# and W is the knapsack's maximum weight.
1+
# This brute-force solution is not as efficient as an approach that uses dynamic
2+
# programming, such as the former example solution in Ruby:
3+
# https://github.com/exercism/ruby/blob/8925745e6301a56cadb49f18b91b19778e9e6642/exercises/practice/knapsack/.meta/example.rb
4+
#
5+
# But this solution is simpler, and the tests still run in <100 ms, so it would
6+
# only be unsuitable for huge input sets.
67
class Knapsack
8+
private attr_reader :max_weight
9+
710
def initialize(max_weight)
811
@max_weight = max_weight
912
end
1013

1114
def max_value(items)
12-
# e.g. max_values[3] is the maximum value so far for a maximum weight of 3.
13-
max_values = Array.new(@max_weight + 1, 0)
14-
15-
items.each do |item|
16-
@max_weight.downto(item.weight) do |weight|
17-
value_with_item = max_values[weight - item.weight] + item.value
18-
19-
max_values[weight] = [max_values[weight], value_with_item].max
20-
end
21-
end
15+
item_combinations = (1..items.length).flat_map { |n| items.combination(n).to_a }
2216

23-
max_values[@max_weight]
17+
item_combinations
18+
.reject { _1.sum(&:weight) > max_weight }
19+
.map { _1.sum(&:value) }
20+
.max || 0
2421
end
2522
end

0 commit comments

Comments
 (0)