给定一个由N个正整数组成的数组arr [] ,任务是最小化可以通过重复删除一对数组元素并用它们的绝对差替换它们而获得的剩余数组元素。
例子:
Input: arr[] ={ 2, 7, 4, 1, 8, 1 }
Output: 1
Explanation:
Removing the pair (arr[0], arr[2]) from arr[] and inserting abs(arr[0] – arr[2]) into arr[] modifies arr[] to { 2, 7, 1, 8, 1 }.
Removing the pair (arr[1], arr[3]) from arr[] and inserting abs(arr[1] – arr[3]) into arr[] modifies arr[] to { 2, 1, 1, 1 }.
Removing the pair (arr[0], arr[1]) from arr[] and inserting abs(arr[0] – arr[1]) into arr[] modifies arr[] to { 1, 1, 1 }.
Removing the pair (arr[0], arr[1]) from arr[] modifies arr[] to { 1 }.
Therefore, the required output is 1.
Input: arr[] = { 1, 1, 4, 2, 2 }
Output: 0
方法:基于以下观察,可以使用动态编程解决问题:
Consider an array arr[] = { a, b, c, d }.
If a > b, then removing the pair (a, b) modifies arr[] to { a – b, c, d }
If c > d, then removing the pair (c, d) modifies arr[] to { a – b, c – d }
If (a – b) > (c – d), then removing the pair (a – b, c – d) modifies arr[] to { (a + d) – (b + c) }
From the above observation, it can be observed that the problem is to partition the array into two subsets with minimum difference of their subset sums.
以下是递归关系:
min_diff(i, sum) = min(min_diff(i – 1, sum + arr[i – 1]), min_diff(i – 1, sum))
where, i : index of array elements
sum : sum of elements of the first subset
请按照以下步骤解决问题:
- 初始化一个二维数组,例如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)