给定一个由N 个正整数和一个正整数K组成的数组arr[] ,任务是找到大小为K 的两个子集中存在的元素总和之间的最小差异,使得每个数组元素最多可以出现在1个子集中.
例子:
Input: arr[] = {12, 3, 5, 6, 7, 17}, K = 2
Output: 1
Explanation: Considering two subsets {5, 6} and {3, 7}, the difference between their sum = (5 + 6) – (3 + 7) = (11 – 10) = 1, which is minimum possible.
Input: arr[] = {10, 10, 10, 10, 10, 2}, K = 3
Output: 8
Explanation: Considering two subsets {10, 10, 10} and {10, 10, 2}, the difference between their sum = (10 + 10 + 10) – (10 + 10 + 2) = (30 – 22) = 8.
朴素方法:解决给定问题的最简单方法是生成大小为K 的所有可能子集,并选择每对大小为 K的子集,使得每个数组元素最多可以出现在1个子集中。找到所有可能的子集对后,打印每对子集的元素总和之间的最小差异。
时间复杂度: O(3 N )
辅助空间: O(1)
高效方法:上述方法可以使用动态规划进行优化。为了实现这种方法,我们的想法是使用 3D 数组,比如dp[][][]来存储每个递归调用的状态。
请按照以下步骤解决问题:
- 初始化一个辅助数组,比如dp[][][] ,其中dp[i][S1][S2]存储形成的两个子集的总和,直到每个第i个索引。
- 声明一个递归函数,比如minimumDifference(arr, N, K1, K2, S1, S2) ,它接受一个数组、数组的当前大小、存储在子集(K1 和 K2)中的元素数量以及总和每个子集中的元素作为参数。
- 基本情况:如果数组中的元素数为N ,并且K1和K2 的值为0 ,则返回S1和S2之间的绝对差值。
- 如果已经计算了当前状态的结果,则返回结果。
- 存储通过在第一个子集中包含第N个元素而返回的值和 递归调用下一次迭代作为minimumDifference(arr, N – 1, K1 – 1, K2, S1 + arr[N – 1], S2) 。
- 存储通过在第一个子集中包含第N个元素而返回的值和 递归调用下一次迭代作为minimumDifference(arr, N – 1, K1, K2 – 1, S1, S2 + arr[N – 1]) 。
- 存储通过不包括任何一个子集中的第N个元素而返回的值,并且 递归调用下一次迭代作为minimumDifference(arr, N – 1, K1, K2, S1, S2) 。
- 存储当前状态下上述三个递归调用返回的所有值中的最小值,即dp[N][S1][S2] ,并返回其值。
- 完成上述步骤后,打印函数minimumDifference(arr, N, K, K, 0, 0)返回的值。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Stores the values at recursive states
int dp[100][100][100];
// Function to find the minimum difference
// between sum of two K-length subsets
int minSumDifference(int* arr, int n,
int k1, int k2,
int sum1, int sum2)
{
// Base Case
if (n < 0) {
// If k1 and k2 are 0, then
// return the absolute difference
// between sum1 and sum2
if (k1 == 0 && k2 == 0) {
return abs(sum1 - sum2);
}
// Otherwise, return INT_MAX
else {
return INT_MAX;
}
}
// If the result is already
// computed, return the result
if (dp[n][sum1][sum2] != -1) {
return dp[n][sum1][sum2];
}
// Store the 3 options
int op1 = INT_MAX;
int op2 = INT_MAX;
int op3 = INT_MAX;
// Including the element in first subset
if (k1 > 0) {
op1 = minSumDifference(arr, n - 1,
k1 - 1, k2,
sum1 + arr[n],
sum2);
}
// Including the element in second subset
if (k2 > 0) {
op2 = minSumDifference(arr, n - 1,
k1, k2 - 1, sum1,
sum2 + arr[n]);
}
// Not including the current element
// in both the subsets
op3 = minSumDifference(arr, n - 1,
k1, k2,
sum1, sum2);
// Store minimum of 3 values obtained
dp[n][sum1][sum2] = min(op1,
min(op2,
op3));
// Return the value for
// the current states
return dp[n][sum1][sum2];
}
// Driver Code
int main()
{
int arr[] = { 12, 3, 5, 6, 7, 17 };
int K = 2;
int N = sizeof(arr) / sizeof(arr[0]);
memset(dp, -1, sizeof(dp));
cout << minSumDifference(arr, N - 1,
K, K, 0, 0);
return 0;
}
Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class GFG{
// Stores the values at recursive states
static int[][][] dp = new int[100][100][100];
// Function to find the minimum difference
// between sum of two K-length subsets
static int minSumDifference(int[] arr, int n,
int k1, int k2,
int sum1, int sum2)
{
// Base Case
if (n < 0)
{
// If k1 and k2 are 0, then
// return the absolute difference
// between sum1 and sum2
if (k1 == 0 && k2 == 0)
{
return Math.abs(sum1 - sum2);
}
// Otherwise, return INT_MAX
else
{
return Integer.MAX_VALUE;
}
}
// If the result is already
// computed, return the result
if (dp[n][sum1][sum2] != -1)
{
return dp[n][sum1][sum2];
}
// Store the 3 options
int op1 = Integer.MAX_VALUE;
int op2 = Integer.MAX_VALUE;
int op3 = Integer.MAX_VALUE;
// Including the element in first subset
if (k1 > 0)
{
op1 = minSumDifference(arr, n - 1,
k1 - 1, k2,
sum1 + arr[n],
sum2);
}
// Including the element in second subset
if (k2 > 0)
{
op2 = minSumDifference(arr, n - 1,
k1, k2 - 1, sum1,
sum2 + arr[n]);
}
// Not including the current element
// in both the subsets
op3 = minSumDifference(arr, n - 1,
k1, k2,
sum1, sum2);
// Store minimum of 3 values obtained
dp[n][sum1][sum2] = Math.min(op1,
Math.min(op2, op3));
// Return the value for
// the current states
return dp[n][sum1][sum2];
}
// Driver Code
public static void main (String[] args)
{
int arr[] = { 12, 3, 5, 6, 7, 17 };
int K = 2;
int N = arr.length;
for(int[][] row:dp)
{
for(int[] innerrow : row)
{
Arrays.fill(innerrow,-1);
}
}
System.out.println(minSumDifference(arr, N - 1, K,
K, 0, 0));
}
}
// This code is contributed by avanitrachhadiya2155
Python3
# Python3 program for the above approach
import sys
# Stores the values at recursive states
dp = [[[ -1 for i in range(100)]
for i in range(100)]
for i in range(100)]
# Function to find the minimum difference
# between sum of two K-length subsets
def minSumDifference(arr, n, k1, k2, sum1, sum2):
global dp
# Base Case
if (n < 0):
# If k1 and k2 are 0, then
# return the absolute difference
# between sum1 and sum2
if (k1 == 0 and k2 == 0):
return abs(sum1 - sum2)
# Otherwise, return INT_MAX
else:
return sys.maxsize + 1
# If the result is already
# computed, return the result
if (dp[n][sum1][sum2] != -1):
return dp[n][sum1][sum2]
# Store the 3 options
op1 = sys.maxsize + 1
op2 = sys.maxsize + 1
op3 = sys.maxsize + 1
# Including the element in first subset
if (k1 > 0):
op1 = minSumDifference(arr, n - 1, k1 - 1,
k2, sum1 + arr[n], sum2)
# Including the element in second subset
if (k2 > 0):
op2 = minSumDifference(arr, n - 1, k1, k2 - 1,
sum1, sum2 + arr[n])
# Not including the current element
# in both the subsets
op3 = minSumDifference(arr, n - 1, k1,
k2, sum1, sum2)
# Store minimum of 3 values obtained
dp[n][sum1][sum2] = min(op1, min(op2, op3))
# Return the value for
# the current states
return dp[n][sum1][sum2]
# Driver Code
if __name__ == '__main__':
arr = [12, 3, 5, 6, 7, 17]
K = 2
N = len(arr)
#memset(dp, -1, sizeof(dp))
print (minSumDifference(arr, N - 1, K, K, 0, 0))
# This code is contributed by mohit kumar 29
C#
// C# program for the above approach
using System;
class GFG{
// Stores the values at recursive states
static int[,,] dp = new int[100, 100, 100];
// Function to find the minimum difference
// between sum of two K-length subsets
static int minSumDifference(int[] arr, int n,
int k1, int k2,
int sum1, int sum2)
{
// Base Case
if (n < 0)
{
// If k1 and k2 are 0, then
// return the absolute difference
// between sum1 and sum2
if (k1 == 0 && k2 == 0)
{
return Math.Abs(sum1 - sum2);
}
// Otherwise, return INT_MAX
else
{
return Int32.MaxValue;
}
}
// If the result is already
// computed, return the result
if (dp[n, sum1, sum2] != -1)
{
return dp[n, sum1, sum2];
}
// Store the 3 options
int op1 = Int32.MaxValue;
int op2 = Int32.MaxValue;
int op3 = Int32.MaxValue;
// Including the element in first subset
if (k1 > 0)
{
op1 = minSumDifference(arr, n - 1,
k1 - 1, k2,
sum1 + arr[n],
sum2);
}
// Including the element in second subset
if (k2 > 0)
{
op2 = minSumDifference(arr, n - 1,
k1, k2 - 1, sum1,
sum2 + arr[n]);
}
// Not including the current element
// in both the subsets
op3 = minSumDifference(arr, n - 1,
k1, k2,
sum1, sum2);
// Store minimum of 3 values obtained
dp[n, sum1, sum2] = Math.Min(op1,
Math.Min(op2, op3));
// Return the value for
// the current states
return dp[n, sum1, sum2];
}
// Driver Code
static public void Main()
{
int[] arr = { 12, 3, 5, 6, 7, 17 };
int K = 2;
int N = arr.Length;
for(int i = 0; i < 100; i++)
{
for(int j = 0; j < 100; j++)
{
for(int k = 0; k < 100; k++)
{
dp[i, j, k] = -1;
}
}
}
Console.WriteLine(minSumDifference(arr, N - 1, K,
K, 0, 0));
}
}
// This code is contributed by rag2127
Javascript
1
时间复杂度: O(N*S 2 ),其中S是给定数组元素的总和
辅助空间: O(N*S 2 )
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。