📌  相关文章
📜  通过删除对并用它们的绝对差值替换它们来最小化剩余的数组元素

📅  最后修改于: 2021-05-19 18:26:56             🧑  作者: Mango

给定一个由N个正整数组成的数组arr [] ,任务是最小化可以通过重复删除一对数组元素并用它们的绝对差替换它们而获得的剩余数组元素。

例子:

方法:基于以下观察,可以使用动态编程解决问题:

以下是递归关系:

请按照以下步骤解决问题:

  • 初始化一个二维数组,例如dp [] [] ,以存储可以获取的第i个元素的子集和的最小差
  • 使用上述递归关系并计算dp [N] [sum]的值
  • 最后,将dp [N] [sum]的值打印为所需的总和。

下面是上述方法的实现:

C++
// C++ program to implement
// the above approach
 
 
#include 
using namespace std;
 
 
// Function to find the smallest element
// left in the array by the given oprations
int smallestLeft(int arr[], int total,
     int sum, int i, vector > &dp)
{
     
    // Base Case
    if (i == 0) {
        return abs(total - 2 * sum);
    }
 
    // If this subproblem
    // has occurred previously
    if (dp[i][sum] != -1)
        return dp[i][sum];
 
    // Including i-th array element
    // into the first subset
    int X = smallestLeft(arr, total,
        sum + arr[i - 1], i - 1, dp);
            
    // If i-th array element is not selected               
    int Y = smallestLeft(arr, total,
                    sum, i - 1, dp);
 
     // Update dp[i][sum]
     return dp[i][sum] = min(X, Y);               
}
 
 
// Utility function to find smallest element
// left in the array by the given oprations
int UtilSmallestElement(int arr[], int N)
{
    // Stores sum of
    // the array elements
    int total = 0;
 
    // Traverse the array
    for (int i = 0; i < N; i++) {
 
        // Update total
        total += arr[i];
    }
     
     
    // Stores overlapping
    // subproblems
    vector > dp(N + 1,
          vector(total, -1));
           
           
    cout<< smallestLeft(arr, total,
                         0, N, dp);
     
}
 
// Driver Code
int main()
{
 
    int arr[] = { 2, 7, 4, 1, 8, 1 };
     
    int N = sizeof(arr) / sizeof(arr[0]);
    UtilSmallestElement(arr, N);
    return 0;
}


Java
// Java program for above approach
import java.util.*;
import java.lang.*;
class GFG
{
 
  // Function to find the smallest element
  // left in the array by the given oprations
  static int smallestLeft(int arr[], int total,
                          int sum, int i, int[][] dp)
  {
 
    // Base Case
    if (i == 0)
    {
      return Math.abs(total - 2 * sum);
    }
 
    // If this subproblem
    // has occurred previously
    if (dp[i][sum] != -1)
      return dp[i][sum];
 
    // Including i-th array element
    // into the first subset
    int X = smallestLeft(arr, total,
                         sum + arr[i - 1], i - 1, dp);
 
    // If i-th array element is not selected               
    int Y = smallestLeft(arr, total,
                         sum, i - 1, dp);
 
    // Update dp[i][sum]
    return dp[i][sum] = Math.min(X, Y);               
  }
 
 
  // Utility function to find smallest element
  // left in the array by the given oprations
  static void UtilSmallestElement(int arr[], int N)
  {
 
    // Stores sum of
    // the array elements
    int total = 0;
 
    // Traverse the array
    for (int i = 0; i < N; i++)
    {
 
      // Update total
      total += arr[i];
    }
 
    // Stores overlapping
    // subproblems
    int[][] dp = new int[N + 1][total];
    for(int[] k:dp)
      Arrays.fill(k, -1);  
    System.out.println(smallestLeft(arr, total,
                                    0, N, dp));
  }
 
  // Driver function
  public static void main (String[] args)
  {
    int arr[] = { 2, 7, 4, 1, 8, 1 };
    int N = arr.length;
    UtilSmallestElement(arr, N);
  }
}
 
// This code is contributed by offbeat


Python3
# Python program to implement
# the above approach
 
# function to find the smallest element
# left in the array by the given oprations
def smallestLeft( arr, total, sum, i, dp):
   
    # Base Case
    if (i == 0):
        return abs(total - 2 * sum)
       
    # If this subproblem
    # has occurred previously
    if (dp[i][sum] != -1):
        return dp[i][sum]
       
    # Including i-th array element
    # into the first subset
    X = smallestLeft(arr, total, sum + arr[i - 1], i - 1, dp)
            
    # If i-th array element is not selected               
    Y = smallestLeft(arr, total, sum, i - 1, dp)
 
    #  Update dp[i][sum]
    dp[i][sum] = min(X, Y)
    return dp[i][sum]
 
# Utility function to find smallest element
# left in the array by the given oprations
def UtilSmallestElement(arr, N):
   
    # Stores sum of
    # the array elements
    total = 0
     
    # Traverse the array
    for i in range (0, N):
       
        # Update total
        total += arr[i]
     
    # Stores overlapping
    # subproblems
    dp = [[-1 for y in range(total)] for x in range(N+1)]       
    print(smallestLeft(arr, total, 0, N, dp))
 
# Driver Code
arr = [2, 7, 4, 1, 8, 1 ]
N = len(arr)
UtilSmallestElement(arr, N)
 
# This code is contributed by amreshkumar3.


C#
// C# program for above approach
using System;
public class GFG
{
 
  // Function to find the smallest element
  // left in the array by the given oprations
  static int smallestLeft(int []arr, int total,
                          int sum, int i, int[,] dp)
  {
 
    // Base Case
    if (i == 0)
    {
      return Math.Abs(total - 2 * sum);
    }
 
    // If this subproblem
    // has occurred previously
    if (dp[i,sum] != -1)
      return dp[i,sum];
 
    // Including i-th array element
    // into the first subset
    int X = smallestLeft(arr, total,
                         sum + arr[i - 1], i - 1, dp);
 
    // If i-th array element is not selected               
    int Y = smallestLeft(arr, total,
                         sum, i - 1, dp);
 
    // Update dp[i,sum]
    return dp[i,sum] = Math.Min(X, Y);               
  }
 
 
  // Utility function to find smallest element
  // left in the array by the given oprations
  static void UtilSmallestElement(int []arr, int N)
  {
 
    // Stores sum of
    // the array elements
    int total = 0;
 
    // Traverse the array
    for (int i = 0; i < N; i++)
    {
 
      // Update total
      total += arr[i];
    }
 
    // Stores overlapping
    // subproblems
    int[,] dp = new int[N + 1,total];
    for(int i = 0; i < N + 1; i++)
    {
      for (int j = 0; j < total; j++)
      {
        dp[i, j] = -1;
      }
    }
    Console.WriteLine(smallestLeft(arr, total,
                                   0, N, dp));
  }
 
  // Driver function
  public static void Main(String[] args)
  {
    int []arr = { 2, 7, 4, 1, 8, 1 };
    int N = arr.Length;
    UtilSmallestElement(arr, N);
  }
}
 
// This code is contributed by shikhasingrajput


C++
// C++ program to implement
// the above approach
 
#include 
using namespace std;
 
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
int SmallestElementLeft(int arr[], int N)
{
     
    // Stores sum of array elements
    int totalSum = 0;
     
    // Traverse the array
    for (int i = 0; i < N; i++) {
 
        // Update totalSum
        totalSum += arr[i];
    }
     
    // Stores half of totalSum
    int req = totalSum / 2;
     
     
    // dp[i]: True if sum i can be
// obtained as a subset sum
    bool dp[req + 1];
     
     
    // Initialize dp[] array
    memset(dp, false, sizeof(dp));
 
    // Base case          
    dp[0] = true;
 
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
     
     
    // Traverse the array
    for (int i = 0; i < N; i++) {
         
        // Iterate over all possible value of sum
        for (int j = req; j - arr[i] >= 0; j--) {
 
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
 
            // If sum i can be obtained
            // from array elements
            if (dp[j]) {
 
                // Update reach
                reach = max(reach, j);
            }
        }
    }
 
    return totalSum - (2 * reach);
}
 
// Driver Code
int main()
{
 
    int arr[] = { 2, 2, 2 };
    int N = sizeof(arr) / sizeof(arr[0]);
     
    cout<< SmallestElementLeft(arr, N);
    return 0;
}


Java
// Java program to implement
// the above approach
import java.util.*;
    
class GFG{
    
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
static int SmallestElementLeft(int arr[], int N)
{
     
    // Stores sum of array elements
    int totalSum = 0;
      
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
         
        // Update totalSum
        totalSum += arr[i];
    }
      
    // Stores half of totalSum
    int req = totalSum / 2;
     
    // dp[i]: True if sum i can be
    // obtained as a subset sum
    boolean[] dp = new boolean[req + 1];
      
    // Initialize dp[] array
    Arrays.fill(dp, false);
  
    // Base case          
    dp[0] = true;
  
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
      
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
         
        // Iterate over all possible value of sum
        for(int j = req; j - arr[i] >= 0; j--)
        {
             
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
  
            // If sum i can be obtained
            // from array elements
            if (dp[j])
            {
                 
                // Update reach
                reach = Math.max(reach, j);
            }
        }
    }
    return totalSum - (2 * reach);
}
    
// Driver Code
public static void main(String[] args)
{
    int arr[] = { 2, 2, 2 };
    int N = arr.length;
     
    System.out.print(SmallestElementLeft(arr, N));
}
}
 
// This code is contributed by code_hunt


Python3
# Python3 program to implement
# the above approach
 
# Function to find minimze the remaining
# array element by removing pairs and
# replacing them by their absolute difference
def SmallestElementLeft(arr, N):
 
    # Stores sum of array elements
    totalSum = 0
 
    # Traverse the array
    for i in range(N):
 
        # Update totalSum
        totalSum += arr[i]
 
    # Stores half of totalSum
    req = totalSum // 2
 
 
    # dp[i]: True if sum i can be
# obtained as a subset sum
    dp = [False for i in range(req + 1)]
 
    # Initialize dp[] array
    # memset(dp, false, sizeof(dp));
 
    # Base case
    dp[0] = True
 
    # Stores closest sum that can
    # be obtained as a subset sum
    reach = 0
 
    # Traverse the array
    for i in range(N):
 
        # Iterate over all possible value of sum
        j = req
        while j>=arr[i]:
 
            # Update dp[j]
            dp[j] = dp[j] or dp[j - arr[i]]
 
            # If sum i can be obtained
            # from array elements
            if (dp[j]):
 
                # Update reach
                reach = max(reach, j)
            j -= 1
 
    return totalSum - (2 * reach)
 
# Driver Code
if __name__ == '__main__':
 
    arr = [2, 2, 2]
    N = len(arr)
 
    print(SmallestElementLeft(arr, N))
 
    # This code is contributed by mohit kumar 29


C#
// C# program to implement
// the above approach 
using System; 
class GFG
{
     
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
static int SmallestElementLeft(int[] arr, int N)
{
      
    // Stores sum of array elements
    int totalSum = 0;
       
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
          
        // Update totalSum
        totalSum += arr[i];
    }
       
    // Stores half of totalSum
    int req = totalSum / 2;
      
    // dp[i]: True if sum i can be
    // obtained as a subset sum
    bool[] dp = new bool[req + 1];
       
    // Initialize dp[] array
    for(int i = 0; i < req + 1; i++)
    {
        dp[i] = false;
    }
 
    // Base case          
    dp[0] = true;
   
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
       
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
          
        // Iterate over all possible value of sum
        for(int j = req; j - arr[i] >= 0; j--)
        {
              
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
   
            // If sum i can be obtained
            // from array elements
            if (dp[j])
            {
                  
                // Update reach
                reach = Math.Max(reach, j);
            }
        }
    }
    return totalSum - (2 * reach);
}
     
// Driver Code
public static void Main()
{
    int[] arr = { 2, 2, 2 };
    int N = arr.Length;    
    Console.Write(SmallestElementLeft(arr, N));
}
}
 
// This code is contributed by sanjoy_62.


输出:
1

时间复杂度: O(N * sum),其中sum是数组元素的总和
辅助空间: O(N *总和)

空间优化方法:为了优化上述方法,其思想是使用制表法。请按照以下步骤解决问题:

  • 初始化一个数组,例如dp [] ,其中dp [i]检查和i是否可以作为给定数组的子集的和获得。
  • 遍历数组并计算数组元素的总和,并将其存储在一个变量中,例如totalSum
  • 使用上述递归关系,找到(totalSum] / 2)的最接近值X ,使dp [X]为真。
  • 最后,打印(totalSum – 2 * X)的值

下面是上述方法的实现:

C++

// C++ program to implement
// the above approach
 
#include 
using namespace std;
 
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
int SmallestElementLeft(int arr[], int N)
{
     
    // Stores sum of array elements
    int totalSum = 0;
     
    // Traverse the array
    for (int i = 0; i < N; i++) {
 
        // Update totalSum
        totalSum += arr[i];
    }
     
    // Stores half of totalSum
    int req = totalSum / 2;
     
     
    // dp[i]: True if sum i can be
// obtained as a subset sum
    bool dp[req + 1];
     
     
    // Initialize dp[] array
    memset(dp, false, sizeof(dp));
 
    // Base case          
    dp[0] = true;
 
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
     
     
    // Traverse the array
    for (int i = 0; i < N; i++) {
         
        // Iterate over all possible value of sum
        for (int j = req; j - arr[i] >= 0; j--) {
 
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
 
            // If sum i can be obtained
            // from array elements
            if (dp[j]) {
 
                // Update reach
                reach = max(reach, j);
            }
        }
    }
 
    return totalSum - (2 * reach);
}
 
// Driver Code
int main()
{
 
    int arr[] = { 2, 2, 2 };
    int N = sizeof(arr) / sizeof(arr[0]);
     
    cout<< SmallestElementLeft(arr, N);
    return 0;
}

Java

// Java program to implement
// the above approach
import java.util.*;
    
class GFG{
    
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
static int SmallestElementLeft(int arr[], int N)
{
     
    // Stores sum of array elements
    int totalSum = 0;
      
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
         
        // Update totalSum
        totalSum += arr[i];
    }
      
    // Stores half of totalSum
    int req = totalSum / 2;
     
    // dp[i]: True if sum i can be
    // obtained as a subset sum
    boolean[] dp = new boolean[req + 1];
      
    // Initialize dp[] array
    Arrays.fill(dp, false);
  
    // Base case          
    dp[0] = true;
  
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
      
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
         
        // Iterate over all possible value of sum
        for(int j = req; j - arr[i] >= 0; j--)
        {
             
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
  
            // If sum i can be obtained
            // from array elements
            if (dp[j])
            {
                 
                // Update reach
                reach = Math.max(reach, j);
            }
        }
    }
    return totalSum - (2 * reach);
}
    
// Driver Code
public static void main(String[] args)
{
    int arr[] = { 2, 2, 2 };
    int N = arr.length;
     
    System.out.print(SmallestElementLeft(arr, N));
}
}
 
// This code is contributed by code_hunt

Python3

# Python3 program to implement
# the above approach
 
# Function to find minimze the remaining
# array element by removing pairs and
# replacing them by their absolute difference
def SmallestElementLeft(arr, N):
 
    # Stores sum of array elements
    totalSum = 0
 
    # Traverse the array
    for i in range(N):
 
        # Update totalSum
        totalSum += arr[i]
 
    # Stores half of totalSum
    req = totalSum // 2
 
 
    # dp[i]: True if sum i can be
# obtained as a subset sum
    dp = [False for i in range(req + 1)]
 
    # Initialize dp[] array
    # memset(dp, false, sizeof(dp));
 
    # Base case
    dp[0] = True
 
    # Stores closest sum that can
    # be obtained as a subset sum
    reach = 0
 
    # Traverse the array
    for i in range(N):
 
        # Iterate over all possible value of sum
        j = req
        while j>=arr[i]:
 
            # Update dp[j]
            dp[j] = dp[j] or dp[j - arr[i]]
 
            # If sum i can be obtained
            # from array elements
            if (dp[j]):
 
                # Update reach
                reach = max(reach, j)
            j -= 1
 
    return totalSum - (2 * reach)
 
# Driver Code
if __name__ == '__main__':
 
    arr = [2, 2, 2]
    N = len(arr)
 
    print(SmallestElementLeft(arr, N))
 
    # This code is contributed by mohit kumar 29

C#

// C# program to implement
// the above approach 
using System; 
class GFG
{
     
// Function to find minimze the remaining
// array element by removing pairs and
// replacing them by their absolute difference
static int SmallestElementLeft(int[] arr, int N)
{
      
    // Stores sum of array elements
    int totalSum = 0;
       
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
          
        // Update totalSum
        totalSum += arr[i];
    }
       
    // Stores half of totalSum
    int req = totalSum / 2;
      
    // dp[i]: True if sum i can be
    // obtained as a subset sum
    bool[] dp = new bool[req + 1];
       
    // Initialize dp[] array
    for(int i = 0; i < req + 1; i++)
    {
        dp[i] = false;
    }
 
    // Base case          
    dp[0] = true;
   
    // Stores closest sum that can
    // be obtained as a subset sum
    int reach = 0;
       
    // Traverse the array
    for(int i = 0; i < N; i++)
    {
          
        // Iterate over all possible value of sum
        for(int j = req; j - arr[i] >= 0; j--)
        {
              
            // Update dp[j]
            dp[j] = dp[j] || dp[j - arr[i]];
   
            // If sum i can be obtained
            // from array elements
            if (dp[j])
            {
                  
                // Update reach
                reach = Math.Max(reach, j);
            }
        }
    }
    return totalSum - (2 * reach);
}
     
// Driver Code
public static void Main()
{
    int[] arr = { 2, 2, 2 };
    int N = arr.Length;    
    Console.Write(SmallestElementLeft(arr, N));
}
}
 
// This code is contributed by sanjoy_62.

输出:

2

时间复杂度: O(N * sum),其中sum是数组元素的总和
辅助空间: O(sum)