Make Sum Divisible by P - Two Sum logic on prefix mod
Problem Statement:
Given an array of positive integers nums
, remove the smallest subarray (possibly empty) such that the sum of the remaining elements is divisible by p
. It is not allowed to remove the whole array.
Return the length of the smallest subarray that you need to remove, or -1
if it's impossible.
A subarray is defined as a contiguous block of elements in the array.
Example 1:
Input: nums = [3,1,4,2], p = 6 Output: 1 Explanation: The sum of the elements in nums is 10, which is not divisible by 6. We can remove the subarray [4], and the sum of the remaining elements is 6, which is divisible by 6.
Example 2:
Input: nums = [6,3,5,2], p = 9 Output: 2 Explanation: We cannot remove a single element to get a sum divisible by 9. The best way is to remove the subarray [5,2], leaving us with [6,3] with sum 9.
Example 3:
Input: nums = [1,2,3], p = 3 Output: 0 Explanation: Here the sum is 6. which is already divisible by 3. Thus we do not need to remove anything.
Constraints:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= p <= 109
Solution:
Basically the solution is to find a subarray whose mod equals that of the complete array. Let us call it M. The first task is to find M
.
int M = 0;
for(int num: nums) {M += num; M %= p;}
Now we need to find subarray whose mod equals M
. To do this we use a logic similar to Two Sum. The logic is that while traversing the array, at any position i
we try to find a complement at an earlier index j
in the [0,i)
range.
Say the prefix sum modulus at j
is a variable a
and the prefix sum modulus at i
is a+M
. Then the modulus of the subarray is M and our task is done. Now as we traverse we are going to search for the variable a
assuming the current modulus is a+M
.
So, say at index i
, the current prefix sum modulus is mod
. Then we need to find an index j
where the prefix sum modulus is mod-M
. But this can be negative. So we can just use (mod-M+p) % p
.
To find this complement, we use the exact same logic of Two Sum ie using a hash map.
cpp []
class Solution {
public:
int minSubarray(vector<int>& nums, int p)
{
int M = 0;
for(int num: nums) {M += num; M %= p;}
if(M==0) return 0;
// Now we need to find smallest subarray whose mod is equal to M
int n = nums.size(), mod = 0, res = INT_MAX;
unordered_map<int,int> mods;
for(int i=0; i<n; i++)
{
int num = nums[i];
mod += num; mod %= p;
int complement = (mod+p-M) % p;
if (mods.count(complement)) res = min(res, i-mods[complement]);
if (complement==0) res = min(res, i+1);
mods[mod] = i;
}
if (res==INT_MAX || res==n) return -1;
return res;
}
};