Minimize sum of differences between maximum and minimum elements present in K subsets
Last Updated :
21 Feb, 2023
Given an array arr[] of size N and an integer K, the task is to minimize the sum of the difference between the maximum and minimum element of each subset by splitting the array into K subsets such that each subset consists of unique array elements only.
Examples:
Input: arr[] = { 6, 3, 8, 1, 3, 1, 2, 2 }, K = 4 Output: 6 Explanation: One of the optimal ways to split the array into K(= 4) subsets are { { 1, 2 }, { 2, 3 }, { 6, 8 }, { 1, 4 } }. Sum of difference of maximum and minimum element present in each subset = { (2 - 1) + (3 - 2) + (8 - 6) + (3 - 1) } = 6. Therefore, the required output is 6
Input: arr[] = { 2, 2, 1, 1 }, K = 1 Output: -1
Approach: The problem can be solved using Dynamic Programming with bitmasking. Following are the recurrence relations:
mask: ith bit of mask checks if array element is already selected in a subset or not. l: index of last element selected in a subset. j: index of current element selected in a subset.
If count of set bits in mask mod (N / K) == 1: dp[mask][l] = min(dp[mask][l], dp[mask ^ (1 << l)][j])
Otherwise, dp[mask][j] = min(dp[mask][j], dp[mask ^ (1 << j)][l] + nums[l] - nums[j])
Follow the steps below to solve the problem:
- Iterate over all possible values of mask, i.e. [0, 2N - 1]
- Initialize an array, say n_z_bits[], to store the count of elements already selected in subsets.
- Use the above recurrence relation and fill all possible dp states of the recurrence relation.
- Finally, print the minimum elements from dp[(1 << N ) - 1].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
// Function to minimize the sum of
// difference between maximums and
// minimums of K subsets of an array
int MinimizeSum(vector<int>& nums, int k)
{
// Stores count of elements
// in an array
int n = nums.size();
// Base Case
if (k == n)
return 0;
// Initialize DP[][] array
int inf = 1e9;
vector<vector<int> > dp(1 << n, vector<int>(n, inf));
// Sort the array
sort(nums.begin(), nums.end());
// Mark i-th element as not selected
for (int i = 0; i < n; i++) {
dp[1 << i][i] = 0;
}
// Iterate over all possible
// values of mask
for (int mask = 0; mask < (1 << n); mask++) {
// Store count of set bits
// in mask
vector<int> n_z_bits;
// Store index of element which is
// already selected in a subset
for (int i = 0; i < n; i++) {
if ((mask >> i) & 1) {
n_z_bits.push_back(i);
}
}
// If count of set bits in mask mod (n // k) equal
// to 1
if (n_z_bits.size() % (n / k) == 1) {
for (int i = 0; i < n_z_bits.size(); i++) {
for (int j = i + 1; j < n_z_bits.size();
j++) {
int temp = dp[mask ^ (1 << n_z_bits[j])]
[n_z_bits[i]];
dp[mask][n_z_bits[j]]
= min(dp[mask][n_z_bits[j]], temp);
}
}
}
else {
for (int i = 0; i < n_z_bits.size(); i++) {
for (int j = i + 1; j < n_z_bits.size();
j++) {
if (nums[n_z_bits[i]]
!= nums[n_z_bits[j]]) {
// Check if l-th element
// is already selected or not
int
mask_t
= mask ^ (1 << n_z_bits[j]);
int temp
= (dp[mask_t][n_z_bits[i]]
+ nums[n_z_bits[i]]
- nums[n_z_bits[j]]);
// Update dp[mask][l]
dp[mask][n_z_bits[j]] = min(
dp[mask][n_z_bits[j]], temp);
}
}
}
}
}
// Return minimum element
// from dp[(1 << N) - 1]
int minVal = inf;
for (int i = 0; i < n; i++) {
minVal = min(minVal, dp[(1 << n) - 1][i]);
}
// If dp[-1] is inf then the
// partition is not possible
if (minVal == inf) {
return -1;
}
else {
return 999999999- minVal;
}
}
// Driver Code
int main()
{
// Given array
vector<int> arr = { 6, 3, 8, 1, 3, 1, 2, 2 };
int k = 4;
// Function call
cout << MinimizeSum(arr, k) << endl;
return 0;
}
// This code is contributed by lokeshpotta20.
Java
import java.util.*;
public class GFG
{
// Function to minimize the sum of
// difference between maximums and
// minimums of K subsets of an array
public static int MinimizeSum(List<Integer> nums, int k)
{
// Stores count of elements
// in an array
int n = nums.size();
//Base Case
if (k == n) {
return 0;
}
// Initialize DP[][] array
int inf = 1_000_000_000;
int[][] dp = new int[1 << n][n];
for (int[] row : dp) {
java.util.Arrays.fill(row, inf);
}
// Sort the array
Collections.sort(nums);
// Mark i-th element as not selected
for (int i = 0; i < n; i++) {
dp[1 << i][i] = 0;
}
// Iterate over all possible
// values of mask
for (int mask = 0; mask < (1 << n); mask++)
{
// Store count of set bits
// in mask
List<Integer> n_z_bits = new ArrayList<>();
// Store index of element which is
// already selected in a subset
for (int i = 0; i < n; i++) {
if ((mask >> i & 1) == 1) {
n_z_bits.add(i);
}
}
// If count of set bits in mask mod (n // k) equal
// to 1
if (n_z_bits.size() % (n / k) == 1) {
for (int i = 0; i < n_z_bits.size(); i++) {
for (int j = i + 1; j < n_z_bits.size(); j++) {
int temp = dp[mask ^ (1 << n_z_bits.get(j))][n_z_bits.get(i)];
dp[mask][n_z_bits.get(j)] = Math.min(dp[mask][n_z_bits.get(j)], temp);
}
}
} else {
for (int i = 0; i < n_z_bits.size(); i++) {
for (int j = i + 1; j < n_z_bits.size(); j++) {
if (nums.get(n_z_bits.get(i)) != nums.get(n_z_bits.get(j)))
{
// Check if l-th element
// is already selected or not
int maskT = mask ^ (1 << n_z_bits.get(j));
int temp = (dp[maskT][n_z_bits.get(i)] + nums.get(n_z_bits.get(i)) - nums.get(n_z_bits.get(j)));
// Update dp[mask][l]
dp[mask][n_z_bits.get(j)] = Math.min(dp[mask][n_z_bits.get(j)], temp);
}
}
}
}
}
// Return minimum element
// from dp[(1 << N) - 1]
int minVal = inf;
// If dp[-1] is inf then the
// partition is not possible
for (int i = 0; i < n; i++) {
minVal = Math.min(minVal, dp[(1 << n) - 1][i]);
}
if (minVal == inf) {
return -1;
} else {
return 999999999 - minVal;
}
}
public static void main(String[] args) {
List<Integer> arr = new ArrayList<>();
arr.add(6);arr.add(3);arr.add(8);arr.add(1);
arr.add(3);arr.add(1);arr.add(2);arr.add(2);
int k = 4;
System.out.println(MinimizeSum(arr,k));
}
}
// This code is contributed by anskalyan3.
Python3
# Python program to implement
# the above approach
from itertools import permutations
from itertools import combinations
# Function to minimize the sum of
# difference between maximums and
# minimums of K subsets of an array
def MinimizeSum(nums, k):
# Stores count of elements
# in an array
n = len(nums)
# Base Case
if k == n:
return 0
# Initialize DP[][] array
dp = [[float("inf")] * n for _ in range(1 << n)]
# Sort the array
nums.sort()
# Mark i-th element
# as not selected
for i in range(n):
dp[1 << i][i] = 0
# Iterate over all possible
# values of mask
for mask in range(1 << n):
# Store count of set bits
# in mask
n_z_bits = []
# Store index of element which is
# already selected in a subset
for p, c in enumerate(bin(mask)):
if c == "1":
temp = len(bin(mask)) - p - 1
n_z_bits.append(temp)
# If count of set bits in mask
# mod (n // k) equal to 1
if len(n_z_bits) % (n//k) == 1:
for j, l in permutations(n_z_bits, 2):
temp = dp[mask ^ (1 << l)][j]
dp[mask][l] = min(dp[mask][l], temp)
else:
for j, l in combinations(n_z_bits, 2):
if nums[j] != nums[l]:
# Check if l-th element
# is already selected or not
mask_t = mask ^ (1 << l)
temp = (dp[mask_t][j] +
nums[j] - nums[l])
# Update dp[mask][l]
dp[mask][l] = min(dp[mask][l],
temp)
# Return minimum element
# from dp[(1 << N) - 1]
if min(dp[-1]) != float("inf"):
return min(dp[-1])
# If dp[-1] is inf then the
# partition is not possible
else:
return -1
# Driver Code
if __name__ == "__main__":
# Given array
arr = [ 6, 3, 8, 1, 3, 1, 2, 2 ]
K = 4
# Function call
print(MinimizeSum(arr, K))
C#
using System;
using System.Collections.Generic;
using System.Linq;
public class GFG {
// Function to minimize the sum of
// difference between maximums and
// minimums of K subsets of an array
public static int MinimizeSum(List<int> nums, int k)
{
// Stores count of elements
// in an array
int n = nums.Count;
if (k == n) {
return 0;
}
// Initialize DP[][] array
int inf = 1_000_000_000;
int[][] dp = new int[1 << n][];
for (int i = 0; i < dp.Length; i++) {
dp[i] = new int[n];
for (int j = 0; j < n; j++) {
dp[i][j] = inf;
}
}
// Sort the array
nums.Sort();
// Mark i-th element as not selected
for (int i = 0; i < n; i++) {
dp[1 << i][i] = 0;
}
// Iterate over all possible
// values of mask
for (int mask = 0; mask < (1 << n); mask++) {
// Store count of set bits
// in mask
List<int> n_z_bits = new List<int>();
// Store index of element which is
// already selected in a subset
for (int i = 0; i < n; i++) {
if ((mask >> i & 1) == 1) {
n_z_bits.Add(i);
}
}
// If count of set bits in mask mod (n // k)
// equal
// to 1
if (n_z_bits.Count % (n / k) == 1) {
for (int i = 0; i < n_z_bits.Count; i++) {
for (int j = i + 1; j < n_z_bits.Count;
j++) {
int temp
= dp[mask ^ (1 << n_z_bits[j])]
[n_z_bits[i]];
dp[mask][n_z_bits[j]] = Math.Min(
dp[mask][n_z_bits[j]], temp);
}
}
}
else {
for (int i = 0; i < n_z_bits.Count; i++) {
for (int j = i + 1; j < n_z_bits.Count;
j++) {
if (nums[n_z_bits[i]]
!= nums[n_z_bits[j]]) {
int maskT
= mask ^ (1 << n_z_bits[j]);
int temp
= (dp[maskT][n_z_bits[i]]
+ nums[n_z_bits[i]]
- nums[n_z_bits[j]]);
dp[mask][n_z_bits[j]]
= Math.Min(
dp[mask][n_z_bits[j]],
temp);
}
}
}
}
}
// Return minimum element
// from dp[(1 << N) - 1]
int minVal = inf;
for (int i = 0; i < n; i++) {
minVal = Math.Min(minVal, dp[(1 << n) - 1][i]);
}
// If dp[-1] is inf then the
// partition is not possible
if (minVal == inf) {
return -1;
}
else {
return 999999999 - minVal;
}
}
// Driver Code
static void Main(string[] args)
{
// Given array
List<int> arr
= new List<int>{ 6, 3, 8, 1, 3, 1, 2, 2 };
int k = 4;
Console.WriteLine(MinimizeSum(arr, k));
}
// This code is contributed by Aditya Sharma.
}
JavaScript
// Javascript equivalent
// Function to minimize the sum of
// difference between maximums and
// minimums of K subsets of an array
function MinimizeSum(nums, k) {
// Stores count of elements
// in an array
let n = nums.length;
//Base Case
if (k == n) {
return 0;
}
// Initialize DP[][] array
let inf = 1000000000;
let dp = new Array(1 << n);
for (let i = 0; i < dp.length; i++) {
dp[i] = Array(n).fill(inf);
}
// Sort the array
nums.sort((a, b) => a - b);
// Mark i-th element as not selected
for (let i = 0; i < n; i++) {
dp[1 << i][i] = 0;
}
// Iterate over all possible
// values of mask
for (let mask = 0; mask < (1 << n); mask++) {
// Store count of set bits
// in mask
let n_z_bits = [];
// Store index of element which is
// already selected in a subset
for (let i = 0; i < n; i++) {
if ((mask >> i & 1) == 1) {
n_z_bits.push(i);
}
}
// If count of set bits in mask mod (n // k) equal
// to 1
if (n_z_bits.length % (n / k) == 1) {
for (let i = 0; i < n_z_bits.length; i++) {
for (let j = i + 1; j < n_z_bits.length; j++) {
let temp =
dp[mask ^ (1 << n_z_bits[j])][n_z_bits[i]];
dp[mask][n_z_bits[j]] = Math.min(
dp[mask][n_z_bits[j]],
temp
);
}
}
} else {
for (let i = 0; i < n_z_bits.length; i++) {
for (let j = i + 1; j < n_z_bits.length; j++) {
if (nums[n_z_bits[i]] != nums[n_z_bits[j]]) {
// Check if l-th element
// is already selected or not
let maskT = mask ^ (1 << n_z_bits[j]);
let temp =
dp[maskT][n_z_bits[i]] +
nums[n_z_bits[i]] -
nums[n_z_bits[j]];
// Update dp[mask][l]
dp[mask][n_z_bits[j]] = Math.min(
dp[mask][n_z_bits[j]],
temp
);
}
}
}
}
}
// Return minimum element
// from dp[(1 << N) - 1]
let minVal = inf;
// If dp[-1] is inf then the
// partition is not possible
for (let i = 0; i < n; i++) {
minVal = Math.min(minVal, dp[(1 << n) - 1][i]);
}
if (minVal == inf) {
return -1;
} else {
return 999999999 - minVal;
}
}
let arr = [6,3,8,1,3,1,2,2];
let k = 4;
console.log(MinimizeSum(arr,k));
Time Complexity: O(N^2 * 2N)
Auxiliary Space: O(N^2 * 2N)
/* Complexity Analysis corrected by RainX */
Similar Reads
Minimize count of Subsets with difference between maximum and minimum element not exceeding K Given an array arr[ ] and an integer K, the task is to split the given array into minimum number of subsets having the difference between the maximum and the minimum element ⤠K. Examples: Input: arr[ ] = {1, 3, 7, 9, 10}, K = 3Output: 2Explanation:One of the possible subsets of arr[] are {1, 3} and
5 min read
Minimize the difference between minimum and maximum elements Given an array of N integers and an integer k . It is allowed to modify an element either by increasing or decreasing them by k (only once).The task is to minimize and print the maximum difference between the shortest and longest towers.Examples: Input: arr[] = {1, 10, 8, 5}, k = 2Output : Max heigh
8 min read
Minimize difference between maximum and minimum element of all possible subarrays Given an array arr[ ] of size N, the task is to find the minimum difference between maximum and minimum elements of all possible sized subarrays of arr[ ]. Examples: Input: arr[] = { 5, 14, 7, 10 } Output: 3Explanation: {7, 10} is the subarray having max element = 10 & min element = 7, and their
5 min read
Min difference between maximum and minimum element in all Y size subarrays Given an array arr[] of size N and integer Y, the task is to find a minimum of all the differences between the maximum and minimum elements in all the sub-arrays of size Y. Examples: Input: arr[] = { 3, 2, 4, 5, 6, 1, 9 } Y = 3Output: 2Explanation:All subarrays of length = 3 are:{3, 2, 4} where maxi
15+ min read
Minimize difference between maximum and minimum array elements by exactly K removals Given an array arr[] consisting of N positive integers and an integer K, the task is to minimize the difference between the maximum and minimum element in the given array after removing exactly K elements. Examples: Input: arr[] = {5, 1, 6, 7, 12, 10}, K = 3Output: 2Explanation:Remove elements 12, 1
6 min read