A couple of quick notes:
- Methods in C# should be named
PascalCase
.
mainfunction
isn't a great name. It should be named by what it does
mainfunction_slave
is also a bad name, you shouldn't use underscores in method names in C#
You need to plan your recursion:
- What's the base case?
- What can you make smaller/approach the base case as you go?
The base case is fairly trivial:
If the array has 1 element, return whether that element matches the target.
static int CalculateCombinations(int[] numbers, int target)
{
// trivial solution:
if (numbers.Length == 0)
{
return 0;
}
// base case:
if (numbers.Length == 1)
{
return numbers[0] == target ? 1 : 0;
}
}
Cool, we could now (or even before this) write a test or two:
[TestMethod]
public void CaclculateCombinationsWithSingleElement()
{
var numbers = new[] { 1 };
var target = 1;
var result = YourClass.CalculateCombinations(numbers, target);
Assert.AreEqual(1, result);
}
(I don't use MSTest myself so not sure if the above is 100% correct).
Now you need to think about how to split the problem up. Recursion on a list is almost always making the list smaller at each step.
The number of combinations is:
var count = 0;
for (var i = 0; i < numbers.Length; i++)
{
// are we at a solution ?
if (numbers[i] == target)
{
count++;
}
// find solutions that sum to the current target - the current number
// on remainder of the array
var subArray = numbers.Skip(i + 1).ToArray();
count += CalculateCombinations(subArray, target - numbers[i]);
}
return count;
If you only consider positive integers, it looks like target
is getting smaller too but actually only the numbers
array is getting 'smaller' as negative numbers or 0s don't make target closer to 0.
That makes the whole solution something like:
static int CalculateCombinations(int[] numbers, int target)
{
if (numbers.Length == 0)
{
return 0;
}
if (numbers.Length == 1)
{
return numbers[0] == target ? 1 : 0;
}
var count = 0;
for (var i = 0; i < numbers.Length; i++)
{
if (numbers[i] == target)
{
count++;
}
var subArray = numbers.Skip(i + 1).ToArray();
count += CalculateCombinations(subArray, target - numbers[i]);
}
return count;
}
Update:
On reflection, the base case can simply be an empty array. We don't need to worry about the length = 1 case because it would have been counted in the for loop anyway.
That means the code can be simplified to:
static int CalculateCombinations(int[] numbers, int target)
{
if (numbers.Length == 0)
{
return 0;
}
var count = 0;
for (var i = 0; i < numbers.Length; i++)
{
if (numbers[i] == target)
{
count++;
}
var subArray = numbers.Skip(i + 1).ToArray();
count += CalculateCombinations(subArray, target - numbers[i]);
}
return count;
}
I'd recommend The Little Schemer as a great introduction to recursion. One of the commandments is:
Simplify only after the function is correct.
So I don't feel too bad about overcomplicating it the first time :)
mainfunction(new[] { 1, 1, 1 }, 3)
return 1? \$\endgroup\$