给定一个大小为N的数组arr [] ,任务是找到给定数组所有可能子集的和的中值。
例子:
Input: arr = {2, 3, 3}
Output: 5
Explanation:
Non-Empty Subsets of the given array are: { {2}, {3}, {3}, {2, 3}, {2, 3}, {3, 3}, {2, 3, 3} }.
Possible sum of each subset are:
{ {2}, {3}, {3}, {5}, {5}, {6}, {8} }
Therefore, the median of all possible sum of each subset is 5.
Input: arr = {1, 2, 1}
Output: 2
天真的方法:解决此问题的最简单方法是生成给定数组的所有可能子集,并找到每个子集的元素之和。最后,打印所有可能的子集和的中值。
时间复杂度: O(N * 2 N )
辅助空间: O(N * 2 N )
高效方法:为了优化上述方法,其思想是使用动态编程。以下是动态编程状态与基本情况的关系:
Relation between DP states:
if j ≥ arr[i] then dp[i][j] = dp[i – 1][j] + dp[i – 1][j – arr[i]]
Otherwise, dp[i][j] = dp[i – 1][j]
where dp[i][j] denotes total number of ways to obtain the sum j either by selecting the ith element or not selecting the ith element.
Base case: dp[i][0] = 1
请按照以下步骤解决问题:
- 初始化一个二维数组,例如DP [] [],以存储上述DP状态。
- 使用DP状态之间的上述关系,以自下而上的方式填充所有dp [] []状态。
- 初始化一个数组,例如sumSub [],以存储每个子集的所有可能的和。
- 遍历dp [] []数组,并将所有可能的子集的和存储在sumSub []数组中。
- 对sumSub []数组进行排序。
- 最后,打印sumSub []数组的中间元素。
C++
// C++ program to implement
// the above approach
#include
using namespace std;
// Function to calculate the median of all
// possible subsets by given operations
int findMedianOfsubSum(int arr[], int N)
{
// Stores sum of elements
// of arr[]
int sum=0;
// Traverse the array arr[]
for(int i=0; i < N; i++) {
// Update sum
sum += arr[i];
}
// Sort the array
sort(arr, arr + N);
// DP[i][j]: Stores total number of ways
// to form the sum j by either selecting
// ith element or not selecting ith item.
int dp[N][sum+1];
// Initialize all
// the DP states
memset(dp, 0, sizeof(dp));
// Base case
for(int i=0; i < N; i++) {
// Fill dp[i][0]
dp[i][0] = 1;
}
// Base case
dp[0][arr[0]] = 1;
// Fill all the DP states based
// on the mentioned DP relation
for(int i = 1; i < N; i++) {
for(int j = 1; j <= sum; j++) {
// If j is greater than
// or equal to arr[i]
if(j >= arr[i]) {
// Update dp[i][j]
dp[i][j] = dp[i-1][j] +
dp[i-1][j-arr[i]];
}
else {
// Update dp[i][j]
dp[i][j] = dp[i-1][j];
}
}
}
// Stores all possible
// subset sum
vector sumSub;
// Traverse all possible subset sum
for(int j=1; j <= sum; j++) {
// Stores count of subsets
// whose sum is j
int M = dp[N - 1][j];
// Itearate over the range [1, M]
for(int i = 1; i <= M; i++) {
// Insert j into sumSub
sumSub.push_back(j);
}
}
// Stores middle element of sumSub
int mid = sumSub[sumSub.size() / 2];
return mid;
}
// Driver Code
int main()
{
int arr[] = { 2, 3, 3 };
int N = sizeof(arr) / sizeof(arr[0]);
cout << findMedianOfsubSum(arr, N);
return 0;
}
Java
// Java program to implement
// the above approach
import java.util.*;
class GFG{
// Function to calculate the median of all
// possible subsets by given operations
static int findMedianOfsubSum(int arr[], int N)
{
// Stores sum of elements
// of arr[]
int sum = 0;
// Traverse the array arr[]
for(int i = 0; i < N; i++)
{
// Update sum
sum += arr[i];
}
// Sort the array
Arrays.sort(arr);
// DP[i][j]: Stores total number of ways
// to form the sum j by either selecting
// ith element or not selecting ith item.
int [][]dp = new int[N][sum + 1];
// Initialize all
// the DP states
for(int i = 0; i < N; i++)
{
for(int j = 0; j < sum + 1; j++)
dp[i][j] = 0;
}
// Base case
for(int i = 0; i < N; i++)
{
// Fill dp[i][0]
dp[i][0] = 1;
}
// Base case
dp[0][arr[0]] = 1;
// Fill all the DP states based
// on the mentioned DP relation
for(int i = 1; i < N; i++)
{
for(int j = 1; j <= sum; j++)
{
// If j is greater than
// or equal to arr[i]
if (j >= arr[i])
{
// Update dp[i][j]
dp[i][j] = dp[i - 1][j] +
dp[i - 1][j - arr[i]];
}
else
{
// Update dp[i][j]
dp[i][j] = dp[i - 1][j];
}
}
}
// Stores all possible
// subset sum
Vector sumSub = new Vector();
// Traverse all possible subset sum
for(int j = 1; j <= sum; j++)
{
// Stores count of subsets
// whose sum is j
int M = dp[N - 1][j];
// Itearate over the range [1, M]
for(int i = 1; i <= M; i++)
{
// Insert j into sumSub
sumSub.add(j);
}
}
// Stores middle element of sumSub
int mid = sumSub.get(sumSub.size() / 2);
return mid;
}
// Driver Code
public static void main(String args[])
{
int arr[] = { 2, 3, 3 };
int N = arr.length;
System.out.print(findMedianOfsubSum(arr, N));
}
}
// This code is contributed by ipg2016107
Python3
# Python3 program to implement
# the above approach
# Function to calculate the
# median of all possible subsets
# by given operations
def findMedianOfsubSum(arr, N):
# Stores sum of elements
# of arr[]
sum = 0
# Traverse the array arr[]
for i in range(N):
# Update sum
sum += arr[i]
# Sort the array
arr.sort(reverse = False)
# DP[i][j]: Stores total number
# of ways to form the sum j by
# either selecting ith element
# or not selecting ith item.
dp = [[0 for i in range(sum + 1)]
for j in range(N)]
# Base case
for i in range(N):
# Fill dp[i][0]
dp[i][0] = 1
# Base case
dp[0][arr[0]] = 1
# Fill all the DP states based
# on the mentioned DP relation
for i in range(1, N, 1):
for j in range(1, sum + 1, 1):
# If j is greater than
# or equal to arr[i]
if(j >= arr[i]):
# Update dp[i][j]
dp[i][j] = (dp[i - 1][j] +
dp[i - 1][j - arr[i]])
else:
# Update dp[i][j]
dp[i][j] = dp[i - 1][j]
# Stores all possible
# subset sum
sumSub = []
# Traverse all possible
# subset sum
for j in range(1, sum + 1, 1):
# Stores count of subsets
# whose sum is j
M = dp[N - 1][j]
# Itearate over the
# range [1, M]
for i in range(1, M + 1, 1):
# Insert j into sumSub
sumSub.append(j)
# Stores middle element
# of sumSub
mid = sumSub[len(sumSub) // 2]
return mid
# Driver Code
if __name__ == '__main__':
arr = [2, 3, 3]
N = len(arr)
print(findMedianOfsubSum(arr, N))
# Thsi code is contributed by bgangwar59
C#
// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
class GFG{
// Function to calculate the median of all
// possible subsets by given operations
static int findMedianOfsubSum(int[] arr, int N)
{
// Stores sum of elements
// of arr[]
int sum = 0;
// Traverse the array arr[]
for(int i = 0; i < N; i++)
{
// Update sum
sum += arr[i];
}
// Sort the array
Array.Sort(arr);
// DP[i][j]: Stores total number of ways
// to form the sum j by either selecting
// ith element or not selecting ith item.
int [,]dp = new int[N, sum + 1];
// Initialize all
// the DP states
for(int i = 0; i < N; i++)
{
for(int j = 0; j < sum + 1; j++)
dp[i, j] = 0;
}
// Base case
for(int i = 0; i < N; i++)
{
// Fill dp[i][0]
dp[i, 0] = 1;
}
// Base case
dp[0, arr[0]] = 1;
// Fill all the DP states based
// on the mentioned DP relation
for(int i = 1; i < N; i++)
{
for(int j = 1; j <= sum; j++)
{
// If j is greater than
// or equal to arr[i]
if (j >= arr[i])
{
// Update dp[i][j]
dp[i, j] = dp[i - 1, j] +
dp[i - 1, j - arr[i]];
}
else
{
// Update dp[i][j]
dp[i, j] = dp[i - 1, j];
}
}
}
// Stores all possible
// subset sum
List sumSub = new List();
// Traverse all possible subset sum
for(int j = 1; j <= sum; j++)
{
// Stores count of subsets
// whose sum is j
int M = dp[N - 1, j];
// Itearate over the range [1, M]
for(int i = 1; i <= M; i++)
{
// Insert j into sumSub
sumSub.Add(j);
}
}
// Stores middle element of sumSub
int mid = sumSub[sumSub.Count / 2];
return mid;
}
// Driver code
public static void Main()
{
int[] arr = { 2, 3, 3 };
int N = arr.Length;
Console.Write(findMedianOfsubSum(arr, N));
}
}
// This code is contributed by sanjoy_62
5