Longest Subarray With Sum Divisible By K
Given an arr[] containing n integers and a positive integer k, he problem is to find the longest subarray's length with the sum of the elements divisible by k.
Examples:
Input: arr[] = [2, 7, 6, 1, 4, 5], k = 3
Output: 4
Explanation: The subarray [7, 6, 1, 4] has sum = 18, which is divisible by 3.Input: arr[] = [-2, 2, -5, 12, -11, -1, 7], k = 3
Output: 5
Explanation: The subarray [2, -5, 12, -11, -1], has sum = -3, which is divisible by 3.Input: arr[] = [1, 2, -2], k = 5
Output: 2
Explanation: The subarray is [2, -2] with sum = 0, which is divisible by 2.
Table of Content
[Naive Approach] Using loop- Iterating over all subarrays
Consider all the subarray sums using two nested for loops and return the length of the longest subarray with a sum divisible by k. To avoid overflow while computing the sum of the subarray, we can keep track of (subarray sum % k) and if (subarray sum % k) results to 0, we can use its length to find the longest subarray divisible by k.
// C++ Program to find the longest subarray with sum
// divisible by k by iterating over all subarrays
#include <iostream>
#include <vector>
using namespace std;
int longestSubarrayDivK(vector<int> &arr, int k) {
int res = 0;
for (int i = 0; i < arr.size(); i++) {
// Initialize sum for the current subarray
int sum = 0;
for (int j = i; j < arr.size(); j++) {
// Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
// Update max length if sum is divisible by k
if (sum == 0)
res = max(res, j - i + 1);
}
}
return res;
}
int main() {
vector<int> arr = {2, 7, 6, 1, 4, 5};
int k = 3;
cout << longestSubarrayDivK(arr, k);
return 0;
}
// C Program to find the longest subarray with sum
// divisible by k by iterating over all subarrays
#include <stdio.h>
int longestSubarrayDivK(int arr[], int n, int k) {
int res = 0;
for (int i = 0; i < n; i++) {
// Initialize sum for the current subarray
int sum = 0;
for (int j = i; j < n; j++) {
// Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
// Update max length if sum is divisible by k
if (sum == 0)
res = (res > (j - i + 1)) ? res : (j - i + 1);
}
}
return res;
}
int main() {
int arr[] = {2, 7, 6, 1, 4, 5};
int k = 3;
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", longestSubarrayDivK(arr, n, k));
return 0;
}
// Java Program to find the longest subarray with sum
// divisible by k by iterating over all subarrays
import java.util.*;
class GfG {
static int longestSubarrayDivK(int[] arr, int k) {
int res = 0;
for (int i = 0; i < arr.length; i++) {
// Initialize sum for the current subarray
int sum = 0;
for (int j = i; j < arr.length; j++) {
// Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
// Update max length if sum is divisible by k
if (sum == 0)
res = Math.max(res, j - i + 1);
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {2, 7, 6, 1, 4, 5};
int k = 3;
System.out.println(longestSubarrayDivK(arr, k));
}
}
# Python Program to find the longest subarray with sum
# divisible by k by iterating over all subarrays
def longestSubarrayDivK(arr, k):
res = 0
for i in range(len(arr)):
# Initialize sum for the current subarray
sum = 0
for j in range(i, len(arr)):
# Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
# Update max length if sum is divisible by k
if sum == 0:
res = max(res, j - i + 1)
return res
if __name__ == "__main__":
arr = [2, 7, 6, 1, 4, 5]
k = 3
print(longestSubarrayDivK(arr, k))
// C# Program to find the longest subarray with sum
// divisible by k by iterating over all subarrays
using System;
class GfG {
static int longestSubarrayDivK(int[] arr, int k) {
int res = 0;
for (int i = 0; i < arr.Length; i++) {
// Initialize sum for the current subarray
int sum = 0;
for (int j = i; j < arr.Length; j++) {
// Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
// Update max length if sum is divisible by k
if (sum == 0)
res = Math.Max(res, j - i + 1);
}
}
return res;
}
static void Main(string[] args) {
int[] arr = {2, 7, 6, 1, 4, 5};
int k = 3;
Console.WriteLine(longestSubarrayDivK(arr, k));
}
}
// JavaScript Program to find the longest subarray with sum
// divisible by k by iterating over all subarrays
function longestSubarrayDivK(arr, k) {
let res = 0;
for (let i = 0; i < arr.length; i++) {
// Initialize sum for the current subarray
let sum = 0;
for (let j = i; j < arr.length; j++) {
// Add the current element to the subarray sum
sum = (sum + arr[j]) % k;
// Update max length if sum is divisible by k
if (sum === 0)
res = Math.max(res, j - i + 1);
}
}
return res;
}
// Driver Code
const arr = [2, 7, 6, 1, 4, 5];
const k = 3;
console.log(longestSubarrayDivK(arr, k));
Output
4
Time Complexity: O(n^2)
Auxiliary Space: O(1)
[Expected Approach] Using Prefix Sum modulo k
The idea is to use Prefix Sum Technique along with Hashing. On observing carefully, we can say that if a subarray arr[i…j] has sum divisible by k, then (prefix sum[i] % k) will be equal to the (prefix sum[j] % k). So, we can iterate over arr[] while maintaining a hash map or dictionary to keep track of the first occurrence of of (prefix sum % k) at each index. For each index i, the longest subarray ending at i and having sum divisible by k will be equal to i - first occurrence of (prefix sum[i] % k).
Note: Negative value of (prefix sum mod k) needs to be handled separately in languages like C++, Java, C# and JavaScript, whereas in Python (prefix sum mod k) is always a non-negative value as it takes the sign of the divisor, that is k.
// C++ Code to find longest Subarray With Sum Divisible
// By K using Prefix Sum and Hash map
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
int longestSubarrayDivK(vector<int> &arr, int k) {
int n = arr.size(), res = 0;
unordered_map<int, int> prefIdx;
int sum = 0;
// Iterate over all ending points
for (int i = 0; i < n; i++) {
// prefix sum mod k (handling negative prefix sum)
sum = ((sum + arr[i]) % k + k) % k;
// If sum == 0, then update result with the
// length of subarray arr[0...i]
if (sum == 0)
res = i + 1;
// Update max length for repeating sum
else if (prefIdx.find(sum) != prefIdx.end()) {
res = max(res, i - prefIdx[sum]);
}
// Store the first occurrence of sum
else {
prefIdx[sum] = i;
}
}
return res;
}
int main() {
vector<int> arr = {2, 7, 6, 1, 4, 5};
int k = 3;
cout << longestSubarrayDivK(arr, k);
}
// Java Code to find longest Subarray With Sum Divisible
// By K using Prefix Sum and Hash map
import java.util.HashMap;
import java.util.Map;
class GfG {
static int longestSubarrayDivK(int[] arr, int k) {
int n = arr.length, res = 0;
Map<Integer, Integer> prefIdx = new HashMap<>();
int sum = 0;
// Iterate over all ending points
for (int i = 0; i < n; i++) {
// prefix sum mod k (handling negative prefix sum)
sum = ((sum + arr[i]) % k + k) % k;
// If sum == 0, then update result with the
// length of subarray arr[0...i]
if (sum == 0)
res = i + 1;
// Update max length for repeating sum
else if (prefIdx.containsKey(sum)) {
res = Math.max(res, i - prefIdx.get(sum));
}
// Store the first occurrence of sum
else {
prefIdx.put(sum, i);
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {2, 7, 6, 1, 4, 5};
int k = 3;
System.out.println(longestSubarrayDivK(arr, k));
}
}
# Python Code to find longest Subarray With Sum Divisible
# By K using Prefix Sum and Hash map
def longestSubarrayDivK(arr, k):
n = len(arr)
res = 0
prefIdx = {}
sum = 0
# Iterate over all ending points
for i in range(n):
# prefix sum mod k
sum = (sum + arr[i]) % k
# If sum == 0, then update result with the
# length of subarray arr[0...i]
if sum == 0:
res = i + 1
# Update max length for repeating sum
elif sum in prefIdx:
res = max(res, i - prefIdx[sum])
# Store the first occurrence of sum
else:
prefIdx[sum] = i
return res
if __name__ == "__main__":
arr = [2, 7, 6, 1, 4, 5]
k = 3
print(longestSubarrayDivK(arr, k))
// C# Code to find longest Subarray With Sum Divisible
// By K using Prefix Sum and Hash map
using System;
using System.Collections.Generic;
class GfG {
static int LongestSubarrayDivK(int[] arr, int k) {
int n = arr.Length, res = 0;
Dictionary<int, int> prefIdx = new Dictionary<int, int>();
int sum = 0;
// Iterate over all ending points
for (int i = 0; i < n; i++) {
// prefix sum mod k (handling negative prefix sum)
sum = ((sum + arr[i]) % k + k) % k;
// If sum == 0, then update result with the
// length of subarray arr[0...i]
if (sum == 0)
res = i + 1;
// Update max length for repeating sum
else if (prefIdx.ContainsKey(sum)) {
res = Math.Max(res, i - prefIdx[sum]);
}
// Store the first occurrence of sum
else {
prefIdx[sum] = i;
}
}
return res;
}
static void Main() {
int[] arr = {2, 7, 6, 1, 4, 5};
int k = 3;
Console.WriteLine(LongestSubarrayDivK(arr, k));
}
}
// JavaScript Code to find longest Subarray With Sum Divisible
// By K using Prefix Sum and Hash map
function longestSubarrayDivK(arr, k) {
let n = arr.length, res = 0;
let prefIdx = new Map();
let sum = 0;
// Iterate over all ending points
for (let i = 0; i < n; i++) {
// prefix sum mod k (handling negative prefix sum)
sum = ((sum + arr[i]) % k + k) % k;
// If sum == 0, then update result with the
// length of subarray arr[0...i]
if (sum === 0)
res = i + 1;
// Update max length for repeating sum
else if (prefIdx.has(sum)) {
res = Math.max(res, i - prefIdx.get(sum));
}
// Store the first occurrence of sum
else {
prefIdx.set(sum, i);
}
}
return res;
}
// Driver Code
let arr = [2, 7, 6, 1, 4, 5];
let k = 3;
console.log(longestSubarrayDivK(arr, k));
Output
4
Time Complexity: O(n), as we are iterating over the array only once.
Auxiliary Space: O(min(n, k)), as at most k keys can be present in the hash map or dictionary.