Skip to content
Related Articles

Related Articles

Improve Article

Count ways to split array into two equal sum subarrays by changing sign of any one array element

  • Difficulty Level : Hard
  • Last Updated : 24 Jun, 2021

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++




// 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




// 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




# 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 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

Javascript




<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>
Output: 
2

 

Time Complexity: O(N)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :