Longest Subarray with 0 Sum
Given an array arr[] consisting of both positive and negative integers, the objective is to find the length of the longest subarray whose elements sum is zero.
A subarray is a contiguous part of an array, formed by selecting one or more consecutive elements while maintaining their original order.
Examples:
Input: arr[] = [15, -2, 2, -8, 1, 7, 10]
Output: 5
Explanation: The longest subarray with sum equals to 0 is [-2, 2, -8, 1, 7].Input: arr[] = [1, 2, 3]
Output: 0
Explanation: There is no subarray with 0 sum.Input: arr[] = [1, 0, 3]
Output: 1
Explanation: The longest sub-array with sum equal to 0 is [0].
Table of Content
[Naive Approach] Iterating over all subarrays - O(n2) Time and O(1) Space
We try all possible subarrays using two nested loops. For each subarray, we calculate its sum, and if the sum is zero, we update the maximum length accordingly.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int maxLength(vector<int>& arr) {
int n = arr.size();
int maxLen = 0;
// Loop through each starting point
for (int i = 0; i < n; i++) {
int currSum = 0;
// Try all subarrays starting from 'i'
for (int j = i; j < n; j++) {
currSum += arr[j];
// as currSum becomes 0, update maxLen
if (currSum == 0)
maxLen = max(maxLen, j - i + 1);
}
}
return maxLen;
}
int main() {
vector<int> arr = {15, -2, 2, -8, 1, 7, 10};
cout << maxLength(arr) << endl;
return 0;
}
#include <stdio.h>
int maxLength(int arr[], int n) {
int maxLen = 0;
// Loop through each starting point
for (int i = 0; i < n; i++) {
int currSum = 0;
// Try all subarrays starting from 'i'
for (int j = i; j < n; j++) {
currSum += arr[j];
// If currSum becomes 0, update maxLen if required
if (currSum == 0) {
int length = j - i + 1;
if (length > maxLen)
maxLen = length;
}
}
}
return maxLen;
}
int main() {
int arr[] = {15, -2, 2, -8, 1, 7, 10};
int size = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", maxLength(arr, size));
return 0;
}
class GfG {
static int maxLength(int arr[]) {
int n = arr.length;
int maxLen = 0;
// Loop through each starting point
for (int i = 0; i < n; i++) {
int currSum = 0;
// Try all subarrays starting from 'i'
for (int j = i; j < n; j++) {
// Add the current element to currSum
currSum += arr[j];
// as the currSum is 0, update the maxLen
if (currSum == 0)
maxLen = Math.max(maxLen, j - i + 1);
}
}
return maxLen;
}
public static void main(String[] args) {
int arr[] = {15, -2, 2, -8, 1, 7, 10};
System.out.println(maxLength(arr));
}
}
def maxLength(arr):
n = len(arr)
maxLen = 0
# Loop through each starting point
for i in range(n):
currSum = 0
# Trying all subarrays starting from 'i'
for j in range(i, n):
currSum += arr[j]
# as currSum becomes 0, update maxLen
if currSum == 0:
maxLen = max(maxLen, j - i + 1)
return maxLen
if __name__ == "__main__":
arr = [15, -2, 2, -8, 1, 7, 10]
print(maxLength(arr))
using System;
using System.Collections.Generic;
class GfG {
static int maxLength(List<int> arr) {
int n = arr.Count;
int maxLen = 0;
// Loop through each starting point
for (int i = 0; i < n; i++) {
int currSum = 0;
// Try all subarrays starting from 'i'
for (int j = i; j < n; j++) {
currSum += arr[j];
// as currSum becomes 0, update maxLen
if (currSum == 0)
maxLen = Math.Max(maxLen, j - i + 1);
}
}
return maxLen;
}
static void Main() {
List<int> arr = new List<int> { 15, -2, 2, -8, 1, 7, 10};
Console.WriteLine(maxLength(arr));
}
}
function maxLength(arr) {
let n = arr.length;
let maxLen = 0;
// Loop through each starting point
for (let i = 0; i < n; i++) {
let currSum = 0;
// Try all subarrays starting from 'i'
for (let j = i; j < n; j++) {
currSum += arr[j];
// as currSum becomes 0, update maxLen
if (currSum === 0) {
maxLen = Math.max(maxLen, j - i + 1);
}
}
}
return maxLen;
}
// Driver Code
let arr = [15, -2, 2, -8, 1, 7, 10];
console.log(maxLength(arr));
Output
5
[Expected Approach] Using Hashmap and Prefix Sum - O(n) Time and O(n) Space
The idea is based on the observation that for two different indices i and j (where j > i) if the prefix sums Si and Sj are equal, it means that the sum of the elements between indices i+1 and j is zero. This is because:
- Sj - Si = arr[i+1] + arr[i+2] + …... + arr[j]
- If Si = Sj, then: arr[i+1] + arr[i+2] + …... + arr[j] = 0. [ The subarray sum from i+1 to j is 0. ]
Step-by-step approach:
- Initialize a variable
prefixSum = 0
and a hashmapfirstSeen = {}
. - Insert 0 into the hashmap with index
-1
.
This handles the case where a subarray starting from index0
itself has a sum of zero. - Traverse the array element by element:
- Update the running prefix sum.
- If this prefix sum has not been seen before, store its index in the hashmap.
- If this prefix sum has been seen before, it means the elements between the previous index (where this sum was first seen) and the current index sum to zero.
- Update the maximum length accordingly.
Working:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int maxLength(vector<int>& arr) {
int n = arr.size();
// prefixSum -> first index
unordered_map<int, int> firstSeen;
int prefixSum = 0;
int maxLen = 0;
// insert prefix sum 0 at index -1
// to handle sum from start
firstSeen[0] = -1;
for (int i = 0; i < n; i++) {
prefixSum += arr[i];
// prefix sum has been seen before
if (firstSeen.find(prefixSum) != firstSeen.end()) {
int prevIndex = firstSeen[prefixSum];
int length = i - prevIndex;
maxLen = max(maxLen, length);
}
else {
// Store first occurrence of this prefix sum
firstSeen[prefixSum] = i;
}
}
return maxLen;
}
int main() {
vector<int> arr = {15, -2, 2, -8, 1, 7, 10};
cout << maxLength(arr) << endl;
return 0;
}
import java.util.HashMap;
import java.util.Map;
class GfG {
public static int maxLength(int[] arr) {
int n = arr.length;
// prefixSum -> first index
Map<Integer, Integer> firstSeen = new HashMap<>();
int prefixSum = 0;
int maxLen = 0;
// insert prefix sum 0 at index -1
// to handle sum from start
firstSeen.put(0, -1);
for (int i = 0; i < n; i++) {
prefixSum += arr[i];
// prefix sum has been seen before
if (firstSeen.containsKey(prefixSum)) {
int prevIndex = firstSeen.get(prefixSum);
int length = i - prevIndex;
maxLen = Math.max(maxLen, length);
} else {
// Store first occurrence of this prefix sum
firstSeen.put(prefixSum, i);
}
}
return maxLen;
}
public static void main(String[] args) {
int[] arr = {15, -2, 2, -8, 1, 7, 10};
System.out.println(maxLength(arr));
}
}
def maxLength(arr):
n = len(arr)
# prefixSum -> first index
firstSeen = {}
prefixSum = 0
maxLen = 0
# insert prefix sum 0 at index -1
# to handle sum from start
firstSeen[0] = -1
for i in range(n):
prefixSum += arr[i]
# prefix sum has been seen before
if prefixSum in firstSeen:
prevIndex = firstSeen[prefixSum]
length = i - prevIndex
maxLen = max(maxLen, length)
else:
# Store first occurrence of this prefix sum
firstSeen[prefixSum] = i
return maxLen
if __name__ == "__main__":
arr = [15, -2, 2, -8, 1, 7, 10]
print(maxLength(arr))
using System;
using System.Collections.Generic;
class GfG {
public static int maxLength(List<int> arr) {
int n = arr.Count;
// prefixSum -> first index
Dictionary<int, int> firstSeen =
new Dictionary<int, int>();
int prefixSum = 0;
int maxLen = 0;
// insert prefix sum 0 at index -1
// to handle sum from start
firstSeen[0] = -1;
for (int i = 0; i < n; i++) {
prefixSum += arr[i];
// prefix sum has been seen before
if (firstSeen.ContainsKey(prefixSum)) {
int prevIndex = firstSeen[prefixSum];
int length = i - prevIndex;
maxLen = Math.Max(maxLen, length);
} else {
// Store first occurrence of this prefix sum
firstSeen[prefixSum] = i;
}
}
return maxLen;
}
static void Main() {
List<int> arr = new List<int> {15, -2, 2, -8, 1, 7, 10};
Console.WriteLine(maxLength(arr));
}
}
function maxLength(arr) {
let n = arr.length;
// prefixSum -> first index
let firstSeen = new Map();
let prefixSum = 0;
let maxLen = 0;
// insert prefix sum 0 at index -1
// to handle sum from start
firstSeen.set(0, -1);
for (let i = 0; i < n; i++) {
prefixSum += arr[i];
// prefix sum has been seen before
if (firstSeen.has(prefixSum)) {
let prevIndex = firstSeen.get(prefixSum);
let length = i - prevIndex;
maxLen = Math.max(maxLen, length);
} else {
// Store first occurrence of this prefix sum
firstSeen.set(prefixSum, i);
}
}
return maxLen;
}
// Driver Code
const arr = [15, -2, 2, -8, 1, 7, 10];
console.log(maxLength(arr));
Output
5
Related Articles: