Given an array arr[] consisting of N integers, the task is to count ways to split array into two subarrays of equal sum by changing the sign of any one array element.
Examples:
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
Naive Approach: The simplest approach to solve the problem is to traverse the array and change the sign of every array element one by one and count the number of ways to split array into two equal sum subarrays for every alteration. Finally, print the sum of all possible ways.
Time Complexity: O(N2)
Auxiliary Space: O(1)
Efficient Approach: To optimize the above approach, the idea is to store the prefix sum and suffix sum for every array indices to find the sum of the splitter subarrays in O(1) computational complexity. Follow the steps below to solve the problem:
- Initialize a variable, say count, to store the number of ways to split the array.
- Initialize two variables, say prefixSum and suffixSum, with 0, to store the prefix and suffix sums of both the arrays.
- Initialize two Maps prefixCount and suffixCount to store the count of elements in prefix and suffix arrays.
- Traverse the array arr[] and update the frequency of each element in suffixCount.
- Traverse the array arr[] and perform the following steps:
- Insert arr[i] into the prefixCount map and remove it from suffixCount.
- Add arr[i] to prefixSum and set suffixSum to the difference of the total sum of the array and prefixSum.
- Store the difference between the sum of the subarrays, i.e. prefixSum – suffixSum in a variable, say diff.
- The count of ways to split at the ith index is calculated by:
- If diff is odd, then the array cannot be split.
- If diff is even, then add the value (prefixCount + suffixCount[ -diff / 2]) to count.
- After completing the above steps, the value of count gives the total count of possible splits.
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
// Function to count ways of splitting // 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< int , int > prefixCount;
unordered_map< int , int > 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 program for the above approach import java.util.*;
class GFG{
// Function to count ways of splitting // 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<Integer,Integer> prefixCount = new HashMap<Integer,Integer>();
HashMap<Integer,Integer> suffixCount = new HashMap<Integer,Integer>();
// 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 program for the above approach # Function to count ways of splitting # 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# program for the above approach using System;
using System.Collections.Generic;
class GFG{
// Function to count ways of splitting
// 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< int , int > prefixCount = new Dictionary< int , int >();
Dictionary< int , int > suffixCount = new Dictionary< int , int >();
// 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 |
<script> // JavaScript program for the above approach // Function to count ways of splitting // the array in two subarrays of equal // sum by changing sign of any 1 element function countSubArraySignChange(arr,N)
{ // Stores the count of elements
// in prefix and suffix of array
let prefixCount = new Map();
let suffixCount = new Map();
// Stores the total sum of array
let total = 0;
// Traverse the array
for (let i = N - 1; i >= 0; i--)
{
total += arr[i];
// Increase the frequency of
// current element in suffix
if (suffixCount.has(arr[i])){
suffixCount.set(arr[i], suffixCount.get(arr[i]) + 1);
}
else {
suffixCount.set(arr[i], 1);
}
}
// Stores prefix sum upto
// an index
let prefixSum = 0;
// Stores sum of suffix
// from an index
let suffixSum = 0;
// Stores the count of ways to
// split the array in 2 subarrays
// having equal sum
let count = 0;
// Traverse the array
for (let i = 0; i < N - 1; i++)
{
// Modify prefix sum
prefixSum += arr[i];
// Add arr[i] to prefix Map
if (prefixCount.has(arr[i]))
{
prefixCount.set(arr[i], prefixCount.get(arr[i])+1);
}
else
{
prefixCount.set(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.has(arr[i]))
{
suffixCount.set(arr[i], suffixCount.get(arr[i]) - 1);
}
// Store the difference
// between the subarrays
let 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
let x = (prefixCount.has(diff / 2)?
prefixCount.get(diff / 2):0)
+ (suffixCount.has(-diff / 2)?
suffixCount.get(-diff / 2):0);
// Update the count
count = count + x;
}
}
// Return the count
return count;
} // Driver Code let arr=[2, 2, -3, 3]; let N = arr.length; // Function Call document.write(countSubArraySignChange(arr, N)); // This code is contributed by patel2127 </script> |
2
Time Complexity: O(N)
Auxiliary Space: O(N)
Related Topic: Subarrays, Subsequences, and Subsets in Array