Here is the simplest iterative implementation of Subset sum problem that I could come up with1, as a follow up to this recursive implementation of the same problem:
using System;
using System.Linq;
namespace Exercise
{
class SubsetSumBinaryNumber
{
static void Main(string[] args)
{
int[] arr = { 2, 3, 1, -1 };
PrintSet(arr, "Initial Set:");
int wantedSum = 4;
Console.WriteLine("Wanted sum = {0}", wantedSum);
FindSubsetSum(arr, wantedSum);
}
//-----------------------------------------------------------------------
/* Method: FindSubsetSum(int[] arr, int sum) */
private static void FindSubsetSum(int[] arr, int targetSum)
{
// convert to base
int toBase = 2;
// length of binary number
int length = arr.Length;
// max value of binary number with "arr.Length" digits
int iEnd = (int) Math.Pow(length, 2);
for (int number = 0; number < iEnd; number++)
{
// convert current number to binary array
bool[] binaryNumber = Enumerable.Range(1, length).Select(i => number / (1 << (length - i)) % 2 == 1).ToArray();
// sum all elements with "true" indexes
int currentSum = 0;
for (int j = 0; j < binaryNumber.Length; j++)
{
if(binaryNumber[j] == true)
{
currentSum += arr[j];
}
}
// check for sum and print if equal
if (currentSum == targetSum)
{
PrintSubSet(arr, binaryNumber);
}
}
}
}
}
Input:
-
Output:
Initial Set.
{2 ,3 ,1 ,-1}
Wanted sum = 4
(1 ,3,)
(-1 ,3 ,2)
The algorithm is based on viewing all the combination of indexes of the initial set as a binary number (0
's and 1
's), then in order to go through all the combinations we simply increment through all the consecutive binary values from 0 to 2set cardinality and sum the set elements that match the 1
's in the binary value, check the sum and print them if sum matches the wanted value.
Could the for
loop be reduced in half if both current binary and its complement are checked simultaneously?
What is the complexity of this algorithm?
Any remarks regarding style and optimization will be appreciated.
Helper functions:
/* Method: PrintSubSet(int[] arr, bool[] subSet) */
private static void PrintSubSet(int[] arr, bool[] subSet)
{
Console.Write("(");
for (int i = 0; i < arr.Length; i++)
{
if (subSet[i] == true)
{
Console.Write(arr[i]);
if (i < arr.Length - 1)
{
Console.Write(" ,");
}
}
}
Console.WriteLine(")");
}
//----------------------------------------------------------------------
/* Method: PrintSet(int[] arr, string label = "") */
private static void PrintSet(int[] arr, string label = "")
{
Console.WriteLine(label);
Console.Write("{");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i]);
if (i < arr.Length - 1)
{
Console.Write(" ,");
}
}
Console.WriteLine("}");
}
1. The most of the algorithms (that I could find) use recursion, dynamic programming and other fairly complex iterative approaches.