Partition into k Equal Sum Subsets (original) (raw)

Last Updated : 14 Apr, 2026

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.

Try It Yourselfredirect icon

Table of Content

Using Recursion - O(k*2^n) Time and O(n*k) Space

We **recursively explore 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 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:

**Steps

#include #include #include #include

using namespace std;

bool isKPartitionPossible(vector &arr, vector &subsetSum, vector &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);
}

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;

}

bool isPartK(vector &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 arr = {2, 1, 4, 5, 3, 3}; int k = 3;

if (isPartK(arr, k))
    cout << "true";
else
    cout << "false";

return 0;

}

Java

import java.util.*;

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, last will be valid
        if (currIdx == k - 2)
            return true;

        return isKPartitionPossible(arr, subsetSum, taken,
                                   target, k, n, currIdx + 1, n - 1);
    }

    for (int i = limitIdx; i >= 0; i--) {

        if (taken[i])
            continue;

        int temp = subsetSum[currIdx] + arr[i];

        if (temp <= target) {

            // Choose element
            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 isPartK(int[] arr, int k) {

    int n = arr.length;
    int sum = 0;

    for (int x : arr)
        sum += x;

    // If only one subset is needed
    if (k == 1)
        return true;

    // Invalid case
    if (n < k || sum % k != 0)
        return false;

    int target = sum / k;

    int[] subsetSum = new int[k];
    boolean[] taken = new boolean[n];

    // Initialize first subset with last element
    subsetSum[0] = arr[n - 1];
    taken[n - 1] = true;

    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 (isPartK(arr, k))
        System.out.println("true");
    else
        System.out.println("false");
}

}

Python

from functools import reduce

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)

for i in range(limitIdx, -1, -1):
    if taken[i]:
        continue
    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

def isPartK(arr, k): n = len(arr) sum_val = reduce(lambda x, y: x + y, 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 sum_val % k!= 0:
    return False

target = sum_val // k
subsetSum = [0] * k
taken = [False] * n

# 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)

if name == 'main': arr = [2, 1, 4, 5, 3, 3] k = 3

if isPartK(arr, k):
    print('true')
else:
    print('false')

C#

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
        if (currIdx == k - 2)
            return true;

        return isKPartitionPossible(arr, subsetSum, taken,
                                    target, k, n, currIdx + 1, n - 1);
    }

    for (int i = limitIdx; i >= 0; i--) {

        if (taken[i])
            continue;

        int temp = subsetSum[currIdx] + arr[i];

        if (temp <= target) {

            // Choose element
            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 isPartK(int[] arr, int k) {

    int n = arr.Length;
    int sum = 0;

    foreach (int x in arr)
        sum += x;

    // If only one subset is needed
    if (k == 1)
        return true;

    // Invalid case
    if (n < k || sum % k != 0)
        return false;

    int target = sum / k;

    int[] subsetSum = new int[k];
    bool[] taken = new bool[n];

    // Initialize first subset with last element
    subsetSum[0] = arr[n - 1];
    taken[n - 1] = true;

    return isKPartitionPossible(arr, subsetSum, taken,
                                target, k, n, 0, n - 1);
}

public static void Main() {
    int[] arr = {2, 1, 4, 5, 3, 3};
    int k = 3;

    if (isPartK(arr, k))
        Console.WriteLine("true");
    else
        Console.WriteLine("false");
}

}

JavaScript

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); }

for (let i = limitIdx; i >= 0; i--) {
    if (taken[i])
        continue;
    let 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;

}

function isPartK(arr, k) { let n = arr.length, sum = arr.reduce((a, b) => a + b, 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;

let target = Math.floor(sum / k);
let subsetSum = new Array(k).fill(0);
let taken = new Array(n).fill(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);

}

(function() { let arr = [2, 1, 4, 5, 3, 3]; let k = 3;

if (isPartK(arr, k))
    console.log('true');
else
    console.log('false');

})();

`

Using Bitmasking and DP - O(n*2^n) and O(2^n) Space

The idea is to use **mask to determine the current state. The current state tells us about the **subset already formed (which numbers are already selected).
**For example: arr[] = [2, 1, 4, 3, 5, 6, 2], **mask = (1100101), which means that [2, 1, 5, 2] are already chosen in the current mask.
For any **current state **mask, the **j th element will be added to it based on the following two conditions:

Maintain a table **dp[] such that **dp[i] store the sum of elements in **mask i. So, the dp transitions will be:
**dp[i | (1 << j)] = (dp[i] + arr[j]) % target

#include #include using namespace std;

bool isPartK(vector &arr, int k) { int n = arr.size();

// Return true as the entire array is the answer
if (k == 1)
    return true;
    
if (n < k)
    return false;

int sum = 0;
for (int i = 0; i < n; i++)
    sum += arr[i];

if (sum % k != 0)

    // No such partitions are possible
    return false;

int target = sum / k;

// Initialize dp vector with -1
vector<int> dp(1 << n, -1);

// Sum of empty subset is zero
dp[0] = 0;

// Iterate over all subsets/masks
for (int mask = 0; mask < (1 << n); mask++) {

    // if current mask is invalid, continue
    if (dp[mask] == -1)
        continue;

    // Iterate over all array elements
    for (int i = 0; i < n; i++) {

        // Check if the current element can be added 
          // to the current subset/mask
        if (!(mask & (1 << i)) && dp[mask] + arr[i] <= target) {
            dp[mask | (1 << i)] = (dp[mask] + arr[i]) % target;
        }
    }
}

// If the dp value of all elements used is zero, then
  // partitioning is possible
return dp[(1 << n) - 1] == 0;

}

int main() { vector arr = {2, 1, 4, 5, 3, 3}; int k = 2;

if (isPartK(arr, k)) {
    cout << "true";
}
else {
    cout << "false";
}

}

Java

import java.util.*;

class GFG {

static boolean isPartK(int[] arr, int k) {
    int n = arr.length;

    if (k == 1)
        // Return true as the entire array is the answer
        return true;

    if (n < k)
        return false;

    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += arr[i];

    if (sum % k != 0)
        // No such partitions are possible
        return false;

    int target = sum / k;

    // Initialize dp array with -1
    int[] dp = new int[1 << n];
    Arrays.fill(dp, -1);

    // Sum of empty subset is zero
    dp[0] = 0;

    // Iterate over all subsets/masks
    for (int mask = 0; mask < (1 << n); mask++) {

        // if current mask is invalid, continue
        if (dp[mask] == -1)
            continue;

        // Iterate over all array elements
        for (int i = 0; i < n; i++) {

            // Check if the current element can be added 
            // to the current subset/mask
            if ((mask & (1 << i)) == 0 && dp[mask] + arr[i] <= target) {
                dp[mask | (1 << i)] = (dp[mask] + arr[i]) % target;
            }
        }
    }

    // If all elements used and remainder is zero
    return dp[(1 << n) - 1] == 0;
}

public static void main(String[] args) {
    int[] arr = {2, 1, 4, 5, 3, 3};
    int k = 2;

    if (isPartK(arr, k))
        System.out.println("true");
    else
        System.out.println("false");
}

}

Python

def isPartK(arr, k): n = len(arr)

if k == 1:
    # Return true as the entire array is the answer
    return True
if n < k:
    return False

sum_val = sum(arr)

if sum_val % k!= 0:
    # No such partitions are possible
    return False

target = sum_val // k

# Initialize dp list with -1
dp = [-1] * (1 << n)

# Sum of empty subset is zero
dp[0] = 0

# Iterate over all subsets/masks
for mask in range(1 << n):

    # if current mask is invalid, continue
    if dp[mask] == -1:
        continue

    # Iterate over all array elements
    for i in range(n):

        # Check if the current element can be added 
        # to the current subset/mask
        if not (mask & (1 << i)) and dp[mask] + arr[i] <= target:
            dp[mask | (1 << i)] = (dp[mask] + arr[i]) % target

# If the dp value of all elements used is zero, then
# partitioning is possible
return dp[(1 << n) - 1] == 0

if name == 'main': arr = [2, 1, 4, 5, 3, 3] k = 2

if isPartK(arr, k):
    print('true')
else:
    print('false')

C#

using System;

class GFG {

static bool isPartK(int[] arr, int k) {
    int n = arr.Length;

    if (k == 1)
        // Return true as the entire array is the answer
        return true;

    if (n < k)
        return false;

    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += arr[i];

    if (sum % k != 0)
        // No such partitions are possible
        return false;

    int target = sum / k;

    // Initialize dp array with -1
    int[] dp = new int[1 << n];
    for (int i = 0; i < dp.Length; i++)
        dp[i] = -1;

    // Sum of empty subset is zero
    dp[0] = 0;

    // Iterate over all subsets/masks
    for (int mask = 0; mask < (1 << n); mask++) {

        // if current mask is invalid, continue
        if (dp[mask] == -1)
            continue;

        // Iterate over all array elements
        for (int i = 0; i < n; i++) {

            // Check if the current element can be added 
            // to the current subset/mask
            if ((mask & (1 << i)) == 0 && dp[mask] + arr[i] <= target) {
                dp[mask | (1 << i)] = (dp[mask] + arr[i]) % target;
            }
        }
    }

    // If all elements used and remainder is zero
    return dp[(1 << n) - 1] == 0;
}

public static void Main() {
    int[] arr = {2, 1, 4, 5, 3, 3};
    int k = 2;

    if (isPartK(arr, k))
        Console.WriteLine("true");
    else
        Console.WriteLine("false");
}

}

JavaScript

function isPartK(arr, k) { let n = arr.length;

if (k === 1)
    // Return true as the entire array is the answer
    return true;
if (n < k)
    return false;

let sum = arr.reduce((a, b) => a + b, 0);

if (sum % k!== 0)
    // No such partitions are possible
    return false;

let target = Math.floor(sum / k);

// Initialize dp array with -1
let dp = new Array(1 << n).fill(-1);

// Sum of empty subset is zero
dp[0] = 0;

// Iterate over all subsets/masks
for (let mask = 0; mask < (1 << n); mask++) {

    // if current mask is invalid, continue
    if (dp[mask] === -1)
        continue;

    // Iterate over all array elements
    for (let i = 0; i < n; i++) {

        // Check if the current element can be added 
        // to the current subset/mask
        if ((mask & (1 << i)) === 0 && dp[mask] + arr[i] <= target) {
            dp[mask | (1 << i)] = (dp[mask] + arr[i]) % target;
        }
    }
}

// If the dp value of all elements used is zero, then
// partitioning is possible
return dp[(1 << n) - 1] === 0;

}

function main() { let arr = [2, 1, 4, 5, 3, 3]; let k = 2;

if (isPartK(arr, k)) {
    console.log('true');
} else {
    console.log('false');
}

} main();

`