JavaScript Program to Find Largest Subarray with a Sum Divisible by k
Finding the largest subarray with a sum divisible by a given integer 'k' is a common problem in JavaScript and other programming languages. This task involves identifying a contiguous subarray within an array of integers such that the sum of its elements is divisible by 'k' and is as long as possible. This problem is essential in various scenarios, including optimizing algorithms and data processing.
Examples:
Input: arr[] = {7,1,3,2,9} , k = 3
Output: 4
Explanation: The subarray is {1, 3, 2, 9} with sum 15, which is divisible by 3.
Input: arr[] = { 4, 5}, k = 2
Output: 1
Table of Content
Approach 1: Brute Force Approach
The brute force approach involves generating all possible subarrays and calculating their sums. For each sum, check if it's divisible by 'k' and keep track of the largest subarray found so far.
Example:
function largestSubarraySumDivisibleByK(arr, k) {
let maxLength = 0;
for (let start = 0;
start < arr.length; start++) {
let currentSum = 0;
for (let end = start;
end < arr.length; end++) {
currentSum += arr[end];
if (currentSum % k === 0 &&
(end - start + 1) > maxLength) {
maxLength = end - start + 1;
}
}
}
return maxLength;
}
const arr = [7, 1, 3, 2, 9];
const k = 3;
console.log(largestSubarraySumDivisibleByK(arr, k));
Output
4
Approach 2: Using Prefix Sum
We can use prefix sums to efficiently calculate subarray sums. By storing the cumulative sum of elements up to each position, you can quickly determine the sum of any subarray. To find the largest subarray divisible by 'k', you track the prefix sums modulo 'k' and store the indices where each remainder is first encountered.
function largestSubarraySumDivisibleByK(arr, k) {
const prefixSums = [0];
let currentSum = 0;
let maxLength = 0;
for (let num of arr) {
currentSum = (currentSum + num) % k;
prefixSums.push(currentSum);
}
const remainderIndices = {};
for (let i = 0; i < prefixSums.length; i++) {
if (remainderIndices
.hasOwnProperty(prefixSums[i])) {
maxLength = Math.max(maxLength,
i - remainderIndices[prefixSums[i]]);
} else {
remainderIndices[prefixSums[i]] = i;
}
}
return maxLength;
}
const arr = [7, 1, 3, 2, 9];
const k = 3;
console.log(largestSubarraySumDivisibleByK(arr, k));
Output
4
Approach 3: Using a Hash Map
An efficient approach involves using a hash map to store the prefix sums modulo 'k' and their corresponding indices.
function largestSubarraySumDivisibleByK(arr, k) {
let currentSum = 0;
let maxLength = 0;
const remainderIndices = { 0: -1 };
for (let i = 0; i < arr.length; i++) {
currentSum += arr[i];
const remainder = (currentSum % k + k) % k;
if (remainderIndices
.hasOwnProperty(remainder)) {
maxLength = Math.max(maxLength,
i - remainderIndices[remainder]);
} else {
remainderIndices[remainder] = i;
}
}
return maxLength;
}
const arr = [7, 1, 3, 2, 9];
const k = 3;
console.log(largestSubarraySumDivisibleByK(arr, k));
Output
4
Approach 4: Using Sliding Window Technique
In this approach, we use a sliding window to find the largest subarray whose sum is divisible by a given integer 'k'. The sliding window technique involves maintaining a window of elements and adjusting its size dynamically as we iterate through the array. This approach is particularly useful for handling continuous data streams or when you need to keep track of a specific condition dynamically.
Example: Here is the implementation of the sliding window approach to find the largest subarray with a sum divisible by 'k'.
function largestSubarrayDivisibleByK(arr, k) {
let maxLength = 0;
let currentSum = 0;
// Create a map to store the first occurrence of remainders
let remainderMap = new Map();
remainderMap.set(0, -1);
for (let i = 0; i < arr.length; i++) {
currentSum += arr[i];
// Get the remainder of the current sum
let remainder = ((currentSum % k) + k) % k;
// If this remainder was seen before, update the maxLength
if (remainderMap.has(remainder)) {
maxLength = Math.max(maxLength, i - remainderMap.get(remainder));
} else {
// Store the first occurrence of this remainder
remainderMap.set(remainder, i);
}
}
return maxLength;
}
// Example usage:
const arr1 = [7, 1, 3, 2, 9];
const k1 = 3;
console.log(largestSubarrayDivisibleByK(arr1, k1)); // Output: 4
const arr2 = [4, 5];
const k2 = 2;
console.log(largestSubarrayDivisibleByK(arr2, k2)); // Output: 1
Output
4 1
Approach 5: Two-Pointer Technique
- Prefix Sums with Modulo: Calculate prefix sums and use modulo operations to determine if a subarray's sum is divisible by
k. - Two Pointers: Use two pointers to find the longest subarray where the sum is divisible by
k. The left pointer marks the start of the subarray, and the right pointer expands the subarray.
Steps:
- Calculate Prefix Sums: Calculate cumulative sums and their modulo
k. - Expand and Contract: Use two pointers to maintain a subarray where the sum modulo
kis zero, adjusting pointers based on conditions.
Example:
function largestSubarrayDivisibleByK(arr, k) {
let n = arr.length;
let maxLength = 0;
let prefixSum = 0;
let remainderMap = new Map();
remainderMap.set(0, -1);
for (let i = 0; i < n; i++) {
prefixSum += arr[i];
let remainder = ((prefixSum % k) + k) % k;
if (remainderMap.has(remainder)) {
maxLength = Math.max(maxLength, i - remainderMap.get(remainder));
} else {
remainderMap.set(remainder, i);
}
}
return maxLength;
}
const arr1 = [7, 1, 3, 2, 9];
const k1 = 3;
console.log(largestSubarrayDivisibleByK(arr1, k1));
const arr2 = [4, 5];
const k2 = 2;
console.log(largestSubarrayDivisibleByK(arr2, k2));
Output
4 1