/***********************************************************************
* 元素和是K的倍数的子串的最大长度:
* 给定数组arr和整数K,求元素和是K的倍数的子串的最大长度
* 例:arr=[1,2,3,4,5] K=5
* 子串[5],[2,3],[1,2,3,4],[1,2,3,4,5]的和都是K的倍数
* 所以返回最大长度5
* 元素和是K的倍数的子串的最大长度:
* 给定数组arr和整数K,求元素和是K的倍数的子串的最大长度
* 例:arr=[1,2,3,4,5] K=5
* 子串[5],[2,3],[1,2,3,4],[1,2,3,4,5]的和都是K的倍数
* 所以返回最大长度5
************************************************************************/
//思路:暴力法可以以O(N^2)的时间复杂度求解,考虑更优的解法
// 假设N>M,如果(arr[0]+...+arr[M])%K等于(arr[0]+...+arr[N])%K
// 则(arr[M+1]+...+arr[N])%K肯定等于0
// 所以对于arr[k],前k项和的余数为:(arr[0]+...+arr[k])%K
// arr[k]与第一次等于这个余数的元素arr[i]之间的子串就是满足要求的
// 求取最大长度即可。但数组前应添加一个0元素,否则第一个元素进不到求取范围
#include<iostream>
#include<vector>
using namespace std;
int maxLength(vector<int> arr, int N, int K)
{
int result = 0;
vector<int> fisrtAppear(K);//记录不同余数第一次出现的索引
for (int i = 0; i < K; i++)
fisrtAppear[i] = -1;
fisrtAppear[0] = 0;
int mod = 0;
for (int i = 0; i < N; i++)
{
mod = (mod + arr[i]) % K;
if (fisrtAppear[mod] == -1)
fisrtAppear[mod] = i+1;
else
result = result < (i+1 - fisrtAppear[mod]) ? (i+1 - fisrtAppear[mod]) : result;
}
return result;
}
int main()
{
int N = 5;
vector<int> arr(N);
for (int i = 0; i < N; i++)
arr[i] = i+1;
int K = 5;
cout << maxLength(arr, N, K);
return 0;
}