Partition into k Equal Sum Subsets

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 Yourself
redirect icon

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 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.

Steps

  • Calculate total sum and check base conditions (k == 1, n < k, sum % k != 0)
  • Set target = sum / k and initialize taken[] and subsetSum[]
  • Use recursion to try adding unused elements to the current subset while keeping sum ≤ target
  • If a subset reaches target, move to the next subset; if k-1 subsets are formed, return true
  • Apply backtracking (undo choices) if no valid combination works, and finally return false if partition is not possible.
C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

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

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

Output
true


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 jth element will be added to it based on the following two conditions:

  • The jth bit is not set in the mask (mask & (1<<j) == 0)
  • sum (mask) + arr[j] <= target ( where target = (sum of array elements) / k)

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 

  • Calculate sum, check divisibility by k, set target
  • Use dp[mask] to store current subset sum, initialize dp[0] = 0
  • For each mask, try adding unused element j if sum ≤ target
  • Update: dp[newMask] = (dp[mask] + arr[j]) % target
  • Continue till all masks are processed
  • If final mask is valid → return true, else false
C++
#include <iostream>
#include <vector>
using namespace std;

bool isPartK(vector<int> &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<int> 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();

Output
true
Comment