Minimum subset sum difference


Partition a Set into Two Subsets with Minimum Difference


Problem Statement

Given an array arr[] of size N, the task is to partition it into two subsets such that the absolute difference of their subset sums is minimized.

Return the minimum absolute difference.


Examples

Input: arr[] = {1, 6, 11, 5}
Output: 1
Explanation: Subset1 = {1, 5, 6} = 12; Subset2 = {11} = 11; |12 - 11| = 1

Input: arr[] = {36, 7, 46, 40}
Output: 23

Constraints


Intuition + Choice Diagram

We aim to split the array into two subsets S1 and S2 such that:

|sum(S1) - sum(S2)| is minimized

Since total sum = S = sum of all elements, we try to find all possible subset sums up to S/2 and pick the one that gives minimum difference.


Choice Diagram:

At each index, we have 2 choices:

        f(i, target)
         /       \
  Pick arr[i]   Skip arr[i]
f(i-1, target-arr[i])   f(i-1, target)

IBH Method for Recursion


Approach 1: Recursion (Top Down with IBH)

public class Solution {
    public static boolean isSubsetPossible(int index, int target, int[] arr) {
        if (target == 0) return true;
        if (index == 0) return arr[0] == target;

        boolean notPick = isSubsetPossible(index - 1, target, arr);
        boolean pick = false;
        if (arr[index] <= target) {
            pick = isSubsetPossible(index - 1, target - arr[index], arr);
        }

        return pick || notPick;
    }

    public static int minSubsetSumDifference(int[] arr, int n) {
        int totalSum = 0;
        for (int num : arr) totalSum += num;

        int minDiff = Integer.MAX_VALUE;
        for (int s1 = 0; s1 <= totalSum / 2; s1++) {
            if (isSubsetPossible(n - 1, s1, arr)) {
                int s2 = totalSum - s1;
                minDiff = Math.min(minDiff, Math.abs(s2 - s1));
            }
        }

        return minDiff;
    }
}

Approach 2: Memoization

public class Solution {
    public static int minSubsetSumDifference(int[] arr, int n) {
        int totalSum = 0;
        for (int num : arr) totalSum += num;

        Boolean[][] dp = new Boolean[n][totalSum + 1];

        for (int i = 0; i < n; i++)
            for (int j = 0; j <= totalSum; j++)
                dp[i][j] = null;

        for (int s1 = 0; s1 <= totalSum / 2; s1++) {
            if (isSubsetPossible(n - 1, s1, arr, dp)) {
                int s2 = totalSum - s1;
                return Math.min(Math.abs(s2 - s1), Math.abs(s1 - s2));
            }
        }

        return 0;
    }

    public static boolean isSubsetPossible(int i, int target, int[] arr, Boolean[][] dp) {
        if (target == 0) return true;
        if (i == 0) return arr[0] == target;

        if (dp[i][target] != null) return dp[i][target];

        boolean notPick = isSubsetPossible(i - 1, target, arr, dp);
        boolean pick = false;
        if (arr[i] <= target)
            pick = isSubsetPossible(i - 1, target - arr[i], arr, dp);

        return dp[i][target] = pick || notPick;
    }
}

Approach 3: Tabulation

public class Solution {
    public static int minSubsetSumDifference(int[] arr, int n) {
        int totalSum = 0;
        for (int num : arr) totalSum += num;

        boolean[][] dp = new boolean[n][totalSum + 1];

        for (int i = 0; i < n; i++) dp[i][0] = true;
        if (arr[0] <= totalSum) dp[0][arr[0]] = true;

        for (int i = 1; i < n; i++) {
            for (int target = 1; target <= totalSum; target++) {
                boolean notPick = dp[i - 1][target];
                boolean pick = false;
                if (arr[i] <= target) {
                    pick = dp[i - 1][target - arr[i]];
                }
                dp[i][target] = pick || notPick;
            }
        }

        int minDiff = Integer.MAX_VALUE;
        for (int s1 = 0; s1 <= totalSum / 2; s1++) {
            if (dp[n - 1][s1]) {
                int s2 = totalSum - s1;
                minDiff = Math.min(minDiff, Math.abs(s2 - s1));
            }
        }

        return minDiff;
    }
}

Approach 4: Space Optimization

public class Solution {
    public static int minSubsetSumDifference(int[] arr, int n) {
        int totalSum = 0;
        for (int num : arr) totalSum += num;

        boolean[] prev = new boolean[totalSum + 1];
        prev[0] = true;
        if (arr[0] <= totalSum) prev[arr[0]] = true;

        for (int i = 1; i < n; i++) {
            boolean[] curr = new boolean[totalSum + 1];
            curr[0] = true;
            for (int target = 1; target <= totalSum; target++) {
                boolean notPick = prev[target];
                boolean pick = false;
                if (arr[i] <= target) {
                    pick = prev[target - arr[i]];
                }
                curr[target] = pick || notPick;
            }
            prev = curr;
        }

        int minDiff = Integer.MAX_VALUE;
        for (int s1 = 0; s1 <= totalSum / 2; s1++) {
            if (prev[s1]) {
                int s2 = totalSum - s1;
                minDiff = Math.min(minDiff, Math.abs(s2 - s1));
            }
        }

        return minDiff;
    }
}

Time and Space Complexities

Approach Time Complexity Space Complexity
Recursion O(2^n) O(n)
Memoization O(n * sum) O(n * sum)
Tabulation O(n * sum) O(n * sum)
Space Optimized O(n * sum) O(sum)

Dry Run

For arr = [1, 6, 11, 5], total = 23
Check all sums s1 = 0 to 11 where subset possible → pick the one with |s1 - (23-s1)| minimum.

At s1 = 11, s2 = 12 → minDiff = 1


Conclusion

This is a classic variation of subset sum problem and a base for many DP questions, like:

Mastering this helps in understanding DP on subsets.