给定一个由N个整数组成的数组arr [] ,任务是通过改变任何一个数组元素的符号,来计算将数组拆分为两个相等总和的子数组的方法。
例子:
Input: arr[] = {2, 2, -3, 3}
Output: 2
Explanation:
Changing arr[0] = 2 to arr[0] = -2, the array becomes {-2, 2, -3, 3}. Only 1 possible split is {-2, 2} and {-3, 3}.
Changing arr[1] = 2 to arr[1] = -2, the array becomes {2, -2, -3, 3}. Only 1 possible split is {-2, 2} and {-3, 3}.
Changing arr[2] = -3 to arr[2] = 3, the array becomes {2, 2, 3, 3}. No way to split the array.
Changing arr[3] = 3 to arr[2] = -3, the array becomes {2, 2, -3, -3}. No way to split the array.
Therefore, the total number of ways to split = 1 + 1 + 0 + 0 = 2.
Input: arr[] = {2, 2, 1, -3, 3}
Output: 0
天真的方法:解决问题的最简单方法是遍历数组,并逐个更改每个数组元素的符号,并为每次更改计算将数组分为两个相等的子数组的方式数量。最后,打印所有可能方式的总和。
时间复杂度: O(N 2 )
辅助空间: O(1)
高效方法:为了优化上述方法,其思想是存储每个数组索引的前缀和后缀和,以找到O(1)计算复杂度的拆分器子数组的和。请按照以下步骤解决问题:
- 初始化一个变量,例如count ,以存储拆分数组的方式数量。
- 用0初始化两个变量,例如prefixSum和suffixSum ,以存储两个数组的前缀和后缀和。
- 初始化两个Maps prefixCount和suffixCount,以将元素的计数存储在前缀和后缀数组中。
- 遍历数组arr []并更新suffixCount中每个元素的频率。
- 遍历数组arr []并执行以下步骤:
- 将arr [i]插入prefixCount映射中,然后将其从suffixCount中删除。
- 到prefixSum和组suffixSum添加ARR [I]到阵列和prefixSum的总和之差。
- 将子数组总和之间的差(即prefixSum – suffixSum)存储在变量diff中。
- 在第i个索引处进行拆分的方式数由下式计算:
- 如果diff是奇数,则无法拆分数组。
- 如果diff是偶数,则将值(prefixCount + suffixCount [-diff / 2])添加到count 。
- 完成上述步骤后, count的值给出了可能拆分的总数。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to count ways of spliting
// the array in two subarrays of equal
// sum by changing sign of any 1 element
int countSubArraySignChange(int arr[], int N)
{
// Stores the count of elements
// in prefix and suffix of array
unordered_map prefixCount;
unordered_map suffixCount;
// Stores the total sum of array
int total = 0;
// Traverse the array
for (int i = N - 1; i >= 0; i--) {
total += arr[i];
// Increase the frequency of
// current element in suffix
suffixCount[arr[i]]++;
}
// Stores prefix sum upto
// an index
int prefixSum = 0;
// Stores sum of suffix
// from an index
int suffixSum = 0;
// Stores the count of ways to
// split the array in 2 subarrays
// having equal sum
int count = 0;
// Traverse the array
for (int i = 0; i < N - 1; i++) {
// Modify prefix sum
prefixSum += arr[i];
// Add arr[i] to prefix Map
prefixCount[arr[i]]++;
// Calculate suffix sum by
// subtracting prefix sum
// from total sum of elements
suffixSum = total - prefixSum;
// Remove arr[i] from suffix Map
suffixCount[arr[i]]--;
// Store the difference
// between the subarrays
int diff = prefixSum - suffixSum;
// Check if diff is even or not
if (diff % 2 == 0) {
// Count number of ways to
// split array at index i such
// that subarray sums are same
int x = prefixCount
+ suffixCount[-diff / 2];
// Update the count
count = count + x;
}
}
// Return the count
return count;
}
// Driver Code
int main()
{
int arr[] = { 2, 2, -3, 3 };
int N = sizeof(arr) / sizeof(arr[0]);
// Function Call
cout << countSubArraySignChange(arr, N);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
// Function to count ways of spliting
// the array in two subarrays of equal
// sum by changing sign of any 1 element
static int countSubArraySignChange(int arr[], int N)
{
// Stores the count of elements
// in prefix and suffix of array
HashMap prefixCount = new HashMap();
HashMap suffixCount = new HashMap();
// Stores the total sum of array
int total = 0;
// Traverse the array
for (int i = N - 1; i >= 0; i--)
{
total += arr[i];
// Increase the frequency of
// current element in suffix
if(suffixCount.containsKey(arr[i])){
suffixCount.put(arr[i], suffixCount.get(arr[i]) + 1);
}
else{
suffixCount.put(arr[i], 1);
}
}
// Stores prefix sum upto
// an index
int prefixSum = 0;
// Stores sum of suffix
// from an index
int suffixSum = 0;
// Stores the count of ways to
// split the array in 2 subarrays
// having equal sum
int count = 0;
// Traverse the array
for (int i = 0; i < N - 1; i++)
{
// Modify prefix sum
prefixSum += arr[i];
// Add arr[i] to prefix Map
if(prefixCount.containsKey(arr[i]))
{
prefixCount.put(arr[i], prefixCount.get(arr[i])+1);
}
else
{
prefixCount.put(arr[i], 1);
}
// Calculate suffix sum by
// subtracting prefix sum
// from total sum of elements
suffixSum = total - prefixSum;
// Remove arr[i] from suffix Map
if(suffixCount.containsKey(arr[i]))
{
suffixCount.put(arr[i], suffixCount.get(arr[i]) - 1);
}
// Store the difference
// between the subarrays
int diff = prefixSum - suffixSum;
// Check if diff is even or not
if (diff % 2 == 0)
{
// Count number of ways to
// split array at index i such
// that subarray sums are same
int x = (prefixCount.containsKey(diff / 2)?prefixCount.get(diff / 2):0)
+ (suffixCount.containsKey(-diff / 2)?suffixCount.get(-diff / 2):0);
// Update the count
count = count + x;
}
}
// Return the count
return count;
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 2, 2, -3, 3 };
int N = arr.length;
// Function Call
System.out.print(countSubArraySignChange(arr, N));
}
}
// This code is contributed by 29AjayKumar
Python3
# Python3 program for the above approach
# Function to count ways of spliting
# the array in two subarrays of equal
# sum by changing sign of any 1 element
def countSubArraySignChange(arr, N):
# Stores the count of elements
# in prefix and suffix of array
prefixCount = {}
suffixCount = {}
# Stores the total sum of array
total = 0
# Traverse the array
for i in range(N - 1, -1, -1):
total += arr[i]
# Increase the frequency of
# current element in suffix
suffixCount[arr[i]] = suffixCount.get(arr[i], 0) + 1
# Stores prefix sum upto
# an index
prefixSum = 0
# Stores sum of suffix
# from an index
suffixSum = 0
# Stores the count of ways to
# split the array in 2 subarrays
# having equal sum
count = 0
# Traverse the array
for i in range(N - 1):
# Modify prefix sum
prefixSum += arr[i]
# Add arr[i] to prefix Map
prefixCount[arr[i]] = prefixCount.get(arr[i], 0) + 1
# Calculate suffix sum by
# subtracting prefix sum
# from total sum of elements
suffixSum = total - prefixSum
# Remove arr[i] from suffix Map
suffixCount[arr[i]] -= 1
# Store the difference
# between the subarrays
diff = prefixSum - suffixSum
# Check if diff is even or not
if (diff % 2 == 0):
# Count number of ways to
# split array at index i such
# that subarray sums are same
y, z = 0, 0
if -diff//2 in suffixCount:
y = suffixCount[-dff//2]
if diff//2 in prefixCount:
z = prefixCount
x = z+ y
# Update the count
count = count + x
# Return the count
return count
# Driver Code
if __name__ == '__main__':
arr=[2, 2, -3, 3]
N = len(arr)
# Function Call
print(countSubArraySignChange(arr, N))
# This code is contributed by mohit kumar 29
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
class GFG{
// Function to count ways of spliting
// the array in two subarrays of equal
// sum by changing sign of any 1 element
static int countSubArraySignChange(int []arr, int N)
{
// Stores the count of elements
// in prefix and suffix of array
Dictionary prefixCount = new Dictionary();
Dictionary suffixCount = new Dictionary();
// Stores the total sum of array
int total = 0;
// Traverse the array
for (int i = N - 1; i >= 0; i--)
{
total += arr[i];
// Increase the frequency of
// current element in suffix
if(suffixCount.ContainsKey(arr[i])){
suffixCount[arr[i]] = suffixCount[arr[i]] + 1;
}
else{
suffixCount.Add(arr[i], 1);
}
}
// Stores prefix sum upto
// an index
int prefixSum = 0;
// Stores sum of suffix
// from an index
int suffixSum = 0;
// Stores the count of ways to
// split the array in 2 subarrays
// having equal sum
int count = 0;
// Traverse the array
for (int i = 0; i < N - 1; i++)
{
// Modify prefix sum
prefixSum += arr[i];
// Add arr[i] to prefix Map
if(prefixCount.ContainsKey(arr[i]))
{
prefixCount[arr[i]] = prefixCount[arr[i]] + 1;
}
else
{
prefixCount.Add(arr[i], 1);
}
// Calculate suffix sum by
// subtracting prefix sum
// from total sum of elements
suffixSum = total - prefixSum;
// Remove arr[i] from suffix Map
if(suffixCount.ContainsKey(arr[i]))
{
suffixCount[arr[i]] = suffixCount[arr[i]] - 1;
}
// Store the difference
// between the subarrays
int diff = prefixSum - suffixSum;
// Check if diff is even or not
if (diff % 2 == 0)
{
// Count number of ways to
// split array at index i such
// that subarray sums are same
int x = (prefixCount.ContainsKey(diff / 2)?prefixCount:0)
+ (suffixCount.ContainsKey(-diff / 2)?suffixCount[-diff / 2]:0);
// Update the count
count = count + x;
}
}
// Return the count
return count;
}
// Driver Code
public static void Main(String[] args)
{
int []arr = { 2, 2, -3, 3 };
int N = arr.Length;
// Function Call
Console.Write(countSubArraySignChange(arr, N));
}
}
// This code is contributed by 29AjayKumar
2
时间复杂度: O(N)
辅助空间: O(N)