Partition of a set into K subsets with equal sum
Given an integer array arr[] and an integer k, the task is to check if it is possible to divide the given array into k non-empty subsets of equal sum such that every array element is part of a single subset.
Examples:
Input: arr[] = [2, 1, 4, 5, 6], k = 3
Output: true
Explanation: Possible subsets of the given array are [2, 4], [1, 5] and [6]Input: arr[] = [2, 1, 5, 5, 6], k = 3
Output: false
Explanation: It is not possible to divide above array into 3 parts with equal sum.
Approach:
We can solve this problem recursively by exploring all possible combinations for each of the k subsets. This is achieved by tracking the sum of the current subset and using a boolean array (taken) to check if an element has already been included in a subset or not.
Base Cases:
- if k = 1, the entire array forms the only subset.
- if n < k, it is impossible to divide the array into k subset since there are not enough elements.
- if the total sum of array is not divisible by k, equal partitioning is not feasible.
if these condition are met, the task reduces to dividing the array into k subsets , each with sum equal to arraySum/k.
Recursive Cases:
The recursive function attempts to add elements to each subset:
- If a subset’s sum matches the required value, the function moves to the next subset.
- If a subset doesn’t reach the target, the function backtracks and tries other combinations of elements.
Once k-1 subsets reach the required sum, the remaining elements automatically form the final subset with the desired sum, confirming that partitioning is possible.
This process continues until either all subsets are formed successfully or no valid partitioning is found.
// C++ program to check whether an array can be
// partitioned into K subsets of equal sum
#include <bits/stdc++.h>
using namespace std;
bool isKPartitionPossible(vector<int> &arr, vector<int> &subsetSum,
vector<bool> &taken, int target, int k,
int n, int currIdx, int limitIdx) {
// If the current subset sum matches the target
if (subsetSum[currIdx] == target) {
// If all but one subset are filled, the
// last subset is guaranteed to work
if (currIdx == k - 2)
return true;
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n, currIdx + 1, n - 1);
}
// Try including each element in the current subset
for (int i = limitIdx; i >= 0; i--) {
// Skip if the element is already used
if (taken[i])
continue;
int temp = subsetSum[currIdx] + arr[i];
if (temp <= target) {
// Only proceed if it doesn't exceed the target
taken[i] = true;
subsetSum[currIdx] += arr[i];
if (isKPartitionPossible(arr, subsetSum, taken,
target, k, n, currIdx, i - 1))
return true;
// Backtrack
taken[i] = false;
subsetSum[currIdx] -= arr[i];
}
}
return false;
}
bool isKPartitionPossible(vector<int> &arr, int k) {
int n = arr.size(), sum = accumulate(arr.begin(), arr.end(), 0);
// If only one subset is needed, it's always possible
if (k == 1)
return true;
// Check if partition is impossible
if (n < k || sum % k != 0)
return false;
int target = sum / k;
vector<int> subsetSum(k, 0);
vector<bool> taken(n, false);
// Initialize first subset with the last element
subsetSum[0] = arr[n - 1];
taken[n - 1] = true;
// Recursively check for partitions
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n, 0, n - 1);
}
int main() {
vector<int> arr = {2, 1, 4, 5, 3, 3};
int k = 3;
if (isKPartitionPossible(arr, k))
cout << "true";
else
cout << "false";
return 0;
}
// Java program to check whether an array can be
// partitioned into K subsets of equal sum
import java.util.Arrays;
class GfG {
static boolean
isKPartitionPossible(int[] arr, int[] subsetSum,
boolean[] taken, int target, int k,
int n, int currIdx, int limitIdx) {
// If the current subset sum matches the target
if (subsetSum[currIdx] == target) {
// If all but one subset are filled, the last
// subset is guaranteed to work
if (currIdx == k - 2)
return true;
return isKPartitionPossible(arr, subsetSum,
taken, target, k, n,
currIdx + 1, n - 1);
}
// Try including each element in the current subset
for (int i = limitIdx; i >= 0; i--) {
if (taken[i])
continue;
int temp = subsetSum[currIdx] + arr[i];
if (temp
<= target) {
// Only proceed if it doesn't
// exceed the target
taken[i] = true;
subsetSum[currIdx] += arr[i];
if (isKPartitionPossible(arr, subsetSum,
taken, target, k,
n, currIdx, i - 1))
return true;
// Backtrack
taken[i] = false;
subsetSum[currIdx] -= arr[i];
}
}
return false;
}
static boolean isKPartitionPossible(int[] arr, int k) {
int n = arr.length;
int sum = Arrays.stream(arr).sum();
// If only one subset is needed, it's always
// possible
if (k == 1)
return true;
// Check if partition is impossible
if (n < k || sum % k != 0)
return false;
int target = sum / k;
int[] subsetSum = new int[k];
boolean[] taken = new boolean[n];
// Initialize the first subset with the
// last element
subsetSum[0] = arr[n - 1];
taken[n - 1] = true;
// Recursively check for partitions
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n, 0, n - 1);
}
public static void main(String[] args) {
int[] arr = { 2, 1, 4, 5, 3, 3 };
int k = 3;
if (isKPartitionPossible(arr, k))
System.out.println("true");
else
System.out.println("false");
}
}
# Python3 program to check whether an array can be
# partitioned into K subsets of equal sum
def isKPartitionPossible(arr, subsetSum, taken,\
target, k, n, currIdx, limitIdx):
# If the current subset sum matches the target
if subsetSum[currIdx] == target:
# If all but one subset are filled, the last
# subset is guaranteed to work
if currIdx == k - 2:
return True
return isKPartitionPossible(arr, subsetSum, taken,\
target, k, n, currIdx + 1, n - 1)
# Try including each element in the current subset
for i in range(limitIdx, -1, -1):
# Skip if the element is already used
if taken[i]:
continue
temp = subsetSum[currIdx] + arr[i]
# Only proceed if it doesn't exceed the target
if temp <= target:
taken[i] = True
subsetSum[currIdx] += arr[i]
if isKPartitionPossible(arr, subsetSum, taken,\
target, k, n, currIdx, i - 1):
return True
# Backtrack
taken[i] = False
subsetSum[currIdx] -= arr[i]
return False
def isKPartitionPossibleMain(arr, k):
n = len(arr)
totalSum = sum(arr)
# If only one subset is needed, it's
# always possible
if k == 1:
return True
# Check if partition is impossible
if n < k or totalSum % k != 0:
return False
target = totalSum // k
subsetSum = [0] * k
taken = [False] * n
# Initialize the first subset with the
# last element
subsetSum[0] = arr[-1]
taken[-1] = True
# Recursively check for partitions
return isKPartitionPossible(arr, subsetSum, taken,\
target, k, n, 0, n - 1)
arr = [2, 1, 4, 5, 3, 3]
k = 3
if isKPartitionPossibleMain(arr, k):
print("true")
else:
print("false")
// C# program to check whether an array can be
// partitioned into K subsets of equal sum
using System;
class GfG {
static bool
isKPartitionPossible(int[] arr, int[] subsetSum,
bool[] taken, int target, int k,
int n, int currIdx, int limitIdx) {
// If the current subset sum matches the target
if (subsetSum[currIdx] == target) {
// If all but one subset are filled, the last
// subset is guaranteed to work
if (currIdx == k - 2)
return true;
return isKPartitionPossible(arr, subsetSum,
taken, target, k, n,
currIdx + 1, n - 1);
}
// Try including each element in the current subset
for (int i = limitIdx; i >= 0; i--) {
// Skip if the element is already used
if (taken[i])
continue;
int temp = subsetSum[currIdx] + arr[i];
if (temp <= target) {
taken[i] = true;
subsetSum[currIdx] += arr[i];
if (isKPartitionPossible(arr, subsetSum,
taken, target, k,
n, currIdx, i - 1))
return true;
// Backtrack
taken[i] = false;
subsetSum[currIdx] -= arr[i];
}
}
return false;
}
static bool isKPartitionPossibleMain(int[] arr, int k) {
int n = arr.Length;
int totalSum = 0;
// Calculate the sum of the array
foreach(var num in arr) { totalSum += num; }
// If only one subset is needed, it's always
// possible
if (k == 1)
return true;
// Check if partition is impossible
if (n < k || totalSum % k != 0)
return false;
int target = totalSum / k;
int[] subsetSum = new int[k];
bool[] taken = new bool[n];
// Initialize the first subset with the last element
subsetSum[0] = arr[n - 1];
taken[n - 1] = true;
// Recursively check for partitions
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n, 0, n - 1);
}
static void Main() {
int[] arr = { 2, 1, 4, 5, 3, 3 };
int k = 3;
if (isKPartitionPossibleMain(arr, k))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
// JavaScript program to check whether an array can be
// partitioned into K subsets of equal sum
function isKPartitionPossible(arr, subsetSum, taken, target,
k, n, currIdx, limitIdx) {
// If the current subset sum matches the target
if (subsetSum[currIdx] === target) {
// If all but one subset are filled, the last subset
// is guaranteed to work
if (currIdx === k - 2) {
return true;
}
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n,
currIdx + 1, n - 1);
}
// Try including each element in the current subset
for (let i = limitIdx; i >= 0; i--) {
if (taken[i])
continue;
let temp = subsetSum[currIdx] + arr[i];
if (temp <= target) {
taken[i] = true;
subsetSum[currIdx] += arr[i];
if (isKPartitionPossible(arr, subsetSum, taken,
target, k, n, currIdx,
i - 1)) {
return true;
}
// Backtrack
taken[i] = false;
subsetSum[currIdx] -= arr[i];
}
}
return false;
}
function isKPartitionPossibleMain(arr, k) {
let n = arr.length;
let totalSum = arr.reduce((sum, num) => sum + num, 0);
// If only one subset is needed, it's always possible
if (k === 1)
return true;
// Check if partition is impossible
if (n < k || totalSum % k !== 0)
return false;
let target = totalSum / k;
let subsetSum = new Array(k).fill(0);
let taken = new Array(n).fill(false);
// Initialize the first subset with the last element
subsetSum[0] = arr[n - 1];
taken[n - 1] = true;
// Recursively check for partitions
return isKPartitionPossible(arr, subsetSum, taken,
target, k, n, 0, n - 1);
}
let arr = [ 2, 1, 4, 5, 3, 3 ];
let k = 3;
if (isKPartitionPossibleMain(arr, k)) {
console.log("true");
}
else {
console.log("false");
}
Output
true
Time Complexity: O(k*2^n) For each k subset, The algorithm checks all possible subsets of the array (which is 2^n).
Auxilary Space: O(n) where n is the length of array.
Related article: