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

📅  最后修改于: 2021-04-17 18:41:29             🧑  作者: 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 )