Can Sum example
Write a function "canSum(targetSum, numbers)" that takes in a targetSum and an array of numbers as arguments
The function should return a boolean indicating whether or not it is possible to generate the targetSum using from the array
You may use an element of the array as many times as needed
You may assume that all input numbers are nonnegative
- explanation
Question: calculate canSum(7, [5, 3, 4, 7])
Explanation: if we have a smaller amount of targetSum, then they'll tend to be a smaller, easier problem than a larger number of targets
Answer: true
1. 3 + 4
2. 7
canSum(7, [2, 4]) -> false
canSum(0, [...]) -> true
- graph display of what goes behind the hood for
canSum(7, [5, 3, 4, 7]) -> true
use targetSum for every node
7
/ | | \
7-5=2 7-3=4 7-4=3 7-7=0
/ \ \
4-3=1 4-4=0 3-3=0
when value is 0, it will be our base case and we can return as true
when value is not 0, it will return as false
as long as 1 leaf node returns true, we can stop the task and return the value
- graph display of what goes behind the hood for
canSum(7, [2, 4]) -> false
m = target sum // which is also the number of levels
n = array length
7 1
/ \
7-2=5 7-4=3 * n
/ \ |
5-2=3 5-4=1 3-2=1 * n
|
3-2=1 * n
all leaf nodes as a targetSum value of more than 0 and cannot be reduced further, thus returns false
Naive solution
- time complexity is
O(n^m)
, where m = target sum, n = numbers.length - space complexity is
O(m)
const canSum = (targetSum, numbers) => {
if (targetSum === 0) return true;
if (targetSum < 0) return false;
for (const num of numbers) {
const remainder = targetSum - num;
if (canSum(remainder, numbers)) {
return true;
}
}
return false;
};
console.log(canSum(7, [2, 3])); // true
console.log(canSum(7, [5, 3, 4, 7])); // true
console.log(canSum(7, [2, 4])); // false
console.log(canSum(8, [2, 3, 5])); // true
console.log(canSum(300, [7, 14])); // false
Memoization solution
- time complexity is
O(n*m)
- space complexity is
O(m)
const canSum = (targetSum, numbers, memo = {}) => {
if (targetSum in memo) return memo[targetSum];
if (targetSum === 0) return true;
if (targetSum < 0) return false;
for (const num of numbers) {
const remainder = targetSum - num;
if (canSum(remainder, numbers, memo)) {
memo[targetSum] = true;
return true;
}
}
memo[targetSum] = false;
return false;
};
console.log(canSum(7, [2, 3])); // true
console.log(canSum(7, [5, 3, 4, 7])); // true
console.log(canSum(7, [2, 4])); // false
console.log(canSum(8, [2, 3, 5])); // true
console.log(canSum(300, [7, 14])); // false
Tabulation solution
canSum(7, [5, 3, 4]) -> true
m = targetSum
n = numbers.length
first create an array the size of the target sum + 1
index: 0 1 2 3 4 5 6 7
value: false false false false false false false false
when targetSum is at 0, no sum is required to get 0, therefore return value should be true
index: 0 1 2 3 4 5 6 7
value: true false false false false false false false
look at the 1st element of the array [5, 3, 4] is 5
current index is 0 and value is true
current index (0), can return 0 by not adding
if current value is true, will always return true,
thus 5 steps ahead of the current index, value can be changed to true
index: 0 1 2 3 4 5 6 7
value: true false false false false true false false
look at the 2nd element of the array [5, 3, 4] is 3
current index is 0 and value is true
current index (0), can return 0 by not adding
if current value is true, will always return true,
thus 3 steps ahead of the current index, value can be changed to true
index: 0 1 2 3 4 5 6 7
value: true false false true false true false false
look at the 3rd element of the array [5, 3, 4] is 4
current index is 0 and value is true
current index (0), can return 0 by not adding
if current value is true, will always return true,
thus 4 steps ahead of the current index, value can be changed to true
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
move current value to the next index
look at the 1st element of the array [5, 3, 4] is 5
current index is 1 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
look at the 2nd element of the array [5, 3, 4] is 3
current index is 1 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
look at the 3rd element of the array [5, 3, 4] is 4
current index is 1 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
move current value to the next index
look at the 1st element of the array [5, 3, 4] is 5
current index is 2 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
look at the 2nd element of the array [5, 3, 4] is 3
current index is 2 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
look at the 3rd element of the array [5, 3, 4] is 4
current index is 2 and value is false
if current value is false, nothing needs to be changed
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
move current value to the next index
look at the 1st element of the array [5, 3, 4] is 5
current index is 3 and value is true
therefore this step can be skipped
index: 0 1 2 3 4 5 6 7
value: true false false true true true false false
look at the 2nd element of the array [5, 3, 4] is 3
current index is 3 and value is true
if current value is true, will always return true,
thus 3 steps ahead of the current index, value can be changed to true
index: 0 1 2 3 4 5 6 7
value: true false false true true true true false
look at the 3rd element of the array [5, 3, 4] is 4
current index is 3 and value is true
if current value is true, will always return true,
thus 4 steps ahead of the current index, value can be changed to true
index: 0 1 2 3 4 5 6 7
value: true false false true true true true true
the rest can be skipped since their values are all true
- time complexity is
O(n*m)
- space complexity is
O(m)
const canSum = (targetSum, numbers) => {
const table = Array(targetSum + 1).fill(false);
table[0] = true;
for (let i = 0; i <= targetSum; i++) {
if (table[i]) {
for (let num of numbers) {
table[i + num] = true;
}
}
}
return table[targetSum];
};
console.log(canSum(7, [2, 3])); // true
console.log(canSum(7, [5, 3, 4, 7])); // true
console.log(canSum(7, [2, 4])); // false
console.log(canSum(8, [2, 3, 5])); // true
console.log(canSum(300, [7, 14])); // false