做一题送一题,力扣上不少类似题
首先,这道题的思路和 974 一样(当然有一些变化)。强烈建议对这个问题不熟悉的同学,看一下 974,搞懂以后,再回来看这道题:
假设 nums 的和除以 P,余数是 mod,
如果 mod == 0,答案就是 0。
如果 mod != 0,答案变成了找原数组中的最短连续子数组,使得其数字和除以 P,余数也是 mod。
由于是求解连续子数组和的问题,很容易想到使用前缀和。
我们可以扫描一遍整个数组,计算到每个元素的前缀和。
假设当前前缀和除以 P 的余数是 curmod,为了找到一段连续子数组对 P 的余数是 mod,我们需要找到一段前缀和,对 P 的余数是 targetmod。其中 targetmod 的求法是:
如果 curmod >= mod,很简单:targetmod = curmod - mod;
如果 curmod < mod,我们需要加上一个 P:targetmod = curmod - mod + P;
这样,我们可以保证,当前前缀和减去目标前缀和,剩余的数组对 P 的余数是 mod。我们只需要找最短的这样的数组就好。
最后,为了快速找到一段对 P 的余数为 targetmod 的前缀和,我们使用一个哈希表 table,来存储之前前缀和对 P 的余数和所在的索引。(key 为余数;value 为索引)。
table 在遍历过程中更新,以保证每次在 table 中查找到的,是离当前元素最近的索引,从而保证找到的是“最短”的连续子数组。
我的参考代码(C++):
class Solution {
public:
int minSubarray(vector<int>& nums, int p) {
long long sum = 0;
for(int e: nums) sum += (long long)e;
long long mod = sum % (long long)p;
if(mod == 0ll) return 0;
int res = nums.size();
unordered_map<long long, int> table;
table[0ll] = -1;
sum = 0;
for(int i = 0; i < nums.size(); i ++){
sum += (long long)nums[i];
long long curmod = sum % (long long)p;
table[curmod] = i;
long long targetmod = curmod >= mod ? (curmod - mod) : (curmod - mod + p);
if(table.count(targetmod))
res = min(res, i - table[targetmod]);
}
return res == nums.size() ? -1 : res;
}
};
觉得有帮助请点赞哇!