📌  相关文章
📜  最小化两个 K 长度子集之和之间的差异

📅  最后修改于: 2021-09-03 13:48:54             🧑  作者: Mango

给定一个由N 个正整数和一个正整数K组成的数组arr[] ,任务是找到大小为K 的两个子集中存在的元素总和之间的最小差异,使得每个数组元素最多可以出现在1个子集中.

例子:

朴素方法:解决给定问题的最简单方法是生成大小为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 ,并且K1K2 的值为0 ,则返回S1S2之间的绝对差值。
    • 如果已经计算了当前状态的结果,则返回结果。
    • 存储通过在第一个子集中包含第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


输出:
1

时间复杂度: O(N*S 2 ),其中S给定数组元素总和
辅助空间: O(N*S 2 )

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live