Given a set of positive integers, check if it can be divided into two subsets with equal sum.

For example,

Consider S = {3, 1, 1, 2, 2, 1}
 
We can partition S into two partitions, each having a sum of 5.
 
S1 = {1, 1, 1, 2}
S2 = {2, 3}
 
Note that this solution is not unique. Here’s another solution.
 
S1 = {3, 1, 1}
S2 = {2, 2, 1}

Practice this problem

The partition problem is a special case of the Subset Sum Problem, which itself is a special case of the Knapsack Problem. The idea is to calculate the sum of all elements in the set, say sum. If sum is odd, we can’t divide the array into two sets. If sum is even, check if a subset with sum/2 exists or not. Following is the algorithm to find the subset sum:

Consider each item in the given array one by one, and for each item, there are two possibilities:

  1. Include the current item in the subset and recur for the remaining items with the remaining total.
  2. Exclude the current item from the subset and recur for the remaining items.

Finally, return true if we get a subset by including or excluding the current item; otherwise, return false. The recursion’s base case would be when no items are left, or the sum becomes negative. We return true when the sum becomes 0, i.e., the subset is found.

 
The algorithm can be implemented as follows in C++, Java, and Python:

C++


Download  Run Code

Output:

Set can be partitioned

Java


Download  Run Code

Output:

Set can be partitioned

Python


Download  Run Code

Output:

Set can be partitioned

The time complexity of the above solution is exponential and occupies space in the call stack.

 
The problem has an optimal substructure and also exhibits overlapping subproblems, i.e., the problem can be split into smaller subproblems, and the same subproblems will get computed again and again. We can easily prove this by drawing a recursion tree of the above code.

Dynamic programming can solve this problem by saving subproblem solutions in memory rather than computing them again and again. The idea is to solve smaller subproblems first, then solve larger subproblems from them. The following bottom-up approach computes T[i][j], for each 1 <= i <= n and 1 <= j <= sum, which is true if subset with sum j can be found using items up to first i items. It uses the value of smaller values i and j already computed. It has the same asymptotic runtime as Memoization but no recursion overhead.

 
Following is the C++, Java, and Python program that demonstrates it:

C++


Download  Run Code

Output:

Set can be partitioned

Java


Download  Run Code

Output:

Set can be partitioned

Python


Download  Run Code

Output:

Set can be partitioned

The time complexity of the above bottom-up solution is O(n × sum) and requires O(n × sum) extra space, where n is the size of the input and sum is the sum of all elements in the input.

 
Exercise: Extend the solution to 3-partitions and also print the partitions.

 
References: https://en.wikipedia.org/wiki/Partition_problem