2

I encountered recursive exercises for improving my coding skills and found the following problem.

Given an array of ints, is it possible to choose a group of some of the ints, such that the group sums to the given target? Rather than looking at the whole array, our convention is to consider the part of the array starting at index start and continuing to the end of the array. The caller can specify the whole array simply by passing start as 0. No loops are needed -- the recursive calls progress down the array.

groupSum(0, [2, 4, 8], 10) → true
groupSum(0, [2, 4, 8], 14) → true
groupSum(0, [2, 4, 8], 9) → false

After 2 days work and studying it i had nothing. i checked the given soluton and i still can not understand the solution after debugging it step by step.

public boolean groupSum(int start, int[] nums, int target) {
  // Base case: if there are no numbers left, then there is a
  // solution only if target is 0.
  if (start >= nums.length) return (target == 0);

  // Key idea: nums[start] is chosen or it is not.
  // Deal with nums[start], letting recursion
  // deal with all the rest of the array.

  // Recursive call trying the case that nums[start] is chosen --
  // subtract it from target in the call.
  if (groupSum(start + 1, nums, target - nums[start])) return true;

  // Recursive call trying the case that nums[start] is not chosen.
  if (groupSum(start + 1, nums, target)) return true;

  // If neither of the above worked, it's not possible.
  return false;
} 

The solution is quite short and its logic is combination based. What do you think about it? What is the explanation of the algorithm behind it?

Regards

mehmet riza oz
  • 541
  • 6
  • 18
  • 1
    What is your idea? Have you tried running it to observe what is going on? The **essence** of learning programming is to be **curious** and find out things yourself. Asking other folks is only the *last resort*. Especially when one could get the idea that you are simply dropping your homework here ... like professor asking you to explain what is going on here. – GhostCat Dec 12 '16 at 14:24
  • It checks if the sum of the number that is in the position indicated in the first parameter and some of the others (to the right) can obtain the target. – Mikel Dec 12 '16 at 14:27
  • Yes GhostCat actually you are right. But i wanted to check my understanding and what other developers think. In fact i found a good explanation in a book named the art of computer programming v4. – mehmet riza oz Dec 12 '16 at 14:42

3 Answers3

4

It's just basic backtracking:

if (start >= nums.length) return (target == 0);

- Here we are past all inputs, and we succeeded exactly when the remaining target to fill is 0


if (groupSum(start + 1, nums, target - nums[start])) return true;

- Here, we're attempting to fill the target using the element at position start:

  • shift start to next position
  • subtract the current element from target (this equals including the current element in chosen set)

if (groupSum(start + 1, nums, target)) return true;

- Here, we're attempting the same without using the element at position start


Reading from the last element:

  • if there's no more elements, we succeeded if target is 0
  • otherwise, we succeed if we can match the remaining elements against the target with or without using the current element
Jiri Tousek
  • 12,211
  • 5
  • 29
  • 43
3

So let's say your question is:

  • Can you create a sum of 9 with the numbers [2, 3, 5, 8]?

This question is true if at least one of the following questions is true:

  • Can you create a sum of 9 with the numbers [3, 5, 8]?
  • Can you create a sum of 7 with the numbers [3, 5, 8]?

thus you replaced your initial question about a 4-element-list with two new questions about 3-element-lists.

When you do this three more times, you end up with 16 questions about 0-element-lists. And if for at least one of them the target is zero, then the answer to your initial question is yes.

fafl
  • 7,222
  • 3
  • 27
  • 50
0

It's based on dynamic programming. Basically you break a single problem into many easier-to-solve subproblems.

Here is some explanation of this specific problem: click.

Shadov
  • 5,421
  • 2
  • 19
  • 38
  • The given code does not use dynamic programming, it's just plain recursion. – Jiri Tousek Dec 12 '16 at 14:49
  • Yes, someone intentionally removed global array of solutions, but made function prototype compatible to DP. I suppose next lesson will add global array of solutions and this O(2^N) code will "magically" work in linear time. – Alexander Anikin Dec 12 '16 at 15:12
  • @AlexanderAnikin this is a NP-complete problem. can't make it go linear. – nafas Dec 12 '16 at 15:45
  • @nafas not linear, sure, but not NP-complete. Take a look at Whatazs "click" link. – Alexander Anikin Dec 12 '16 at 16:38
  • Actually this problem can be solved in O(n^2) by creating a HashSet of all possible sums. So it's not NP-complete. You can do it in a one-liner in python: `10 in reduce(lambda acc, val: acc | {x + val for x in acc}, [2, 3, 5, 8], {0})` – fafl Dec 12 '16 at 16:38
  • hmm I think i mixed it up with subset-sum problem – nafas Dec 12 '16 at 16:44
  • @nafas I just saw that my code goes bonkers when the integers are for example the first 20 powers of 2. So you might be right. – fafl Dec 12 '16 at 17:03
  • @AlexanderAnikin I was rigth about this solution be NP-complete, I just read the link and it confirms it. – nafas Dec 12 '16 at 17:19
  • @fafl yeah, its been a long ago since I was studying np-complete, that's why I gave up easily, :D. but yeah its a NP problem – nafas Dec 12 '16 at 17:20
  • @nafas original topic solution has complexity O(N^2), but the problem itself with int sum and weights can be solved in polynomial time (so problem is not NP). DP solution provided in link solves it in O(N*MAX_SUM) time – Alexander Anikin Dec 13 '16 at 13:11
  • @AlexanderAnikin on the link it states : `Time complexity of the above solution is O(sum*n).` name of the problem is subset sum --> https://en.wikipedia.org/wiki/Subset_sum_problem :) – nafas Dec 13 '16 at 13:39