The problem is as follows:
Given an array $A$ of length $N$, $A[i] \ge 0$ ( $0 \le i \le N-1$) , and a number $K$. Find the longest subarray whose sum is divisible by $K$, if there are no such subarray, return 0;
The idea is to traverse the array and record the result of cumulative sum modulo $K$ and its corresponding index. If for index $i, j$, the remainder is the same, then the subarray between $i, j$ must be a valid subarray (i.e., its sum is divisible by $K$). In order to find the longest subarray, we can keep a list of index corresponding to each remainder (there are $K$ remainders, $0, 1, 2, …, K-1$). During the traversing process, we can also easily find the longest subarray (index list of each remainder is stored in ascending order).
Below is the implementation of the above idea:
int findLongestSubarray(vector<int>& nums){
int N = nums.size();
map<int, vector<int>> indexInfo;
index[0].push_back(-1);
// the remainder at current index
int cur_remainder = 0;
int maxLen = 0;
for (int i = 0; i < N; i++) {
cur_remainder = (cur_remainder + nums[i]) % K;
if (indexInfo[cur_remainder].size() != 0){
maxLen = max(maxLen, i - indexInfo[cur_remainder].front());
}
indexInfo[cur_remainder].push_back(i);
}
return maxLen;
}Note that the line index[0].push_back(-1); is needed.
Otherwise, for $A = [3]$ and $k=3$, we can not the right answer.
Time complexity: traversing the array and finding the maxLen during the process takes $O(n)$ time. Space complexity is apparently $O(n)$.
P.S. Thanks to Scott for pointing out that there is no need to sort the list corresponding to each remainder, because they are already in sorted order.
The problem is as follows:
Given an array $A$ of length $N$, $A[i] \ge 0$ ( $0 \le i \le N-1$) , and a number $K$. Find the longest subarray whose sum is divisible by $K$, if there are no such subarray, return 0;
The idea is to traverse the array and record the result of cumulative sum modulo $K$ and its corresponding index. If for index $i, j$, the remainder is the same, then the subarray between $i, j$ must be a valid subarray (i.e., its sum is divisible by $K$). In order to find the longest subarray, we can keep a list of index corresponding to each remainder (there are $K$ remainders, $0, 1, 2, …, K-1$). During the traversing process, we can also easily find the longest subarray (index list of each remainder is stored in ascending order).
Below is the implementation of the above idea:
int findLongestSubarray(vector<int>& nums){
int N = nums.size();
map<int, vector<int>> indexInfo;
index[0].push_back(-1);
// the remainder at current index
int cur_remainder = 0;
int maxLen = 0;
for (int i = 0; i < N; i++) {
cur_remainder = (cur_remainder + nums[i]) % K;
if (indexInfo[cur_remainder].size() != 0){
maxLen = max(maxLen, i - indexInfo[cur_remainder].front());
}
indexInfo[cur_remainder].push_back(i);
}
return maxLen;
}Note that the line index[0].push_back(-1); is needed.
Otherwise, for $A = [3]$ and $k=3$, we can not the right answer.
Time complexity: traversing the array and finding the maxLen during the process takes $O(n)$ time. Space complexity is apparently $O(n)$.
P.S. Thanks to Scott for pointing out that there is no need to sort the list corresponding to each remainder, because they are already in sorted order.