阅读视图

发现新文章,点击刷新页面。

做一题送一题,力扣上不少类似题

首先,这道题的思路和 974 一样(当然有一些变化)。强烈建议对这个问题不熟悉的同学,看一下 974,搞懂以后,再回来看这道题:

974. 和可被 K 整除的子数组


假设 nums 的和除以 P,余数是 mod

如果 mod == 0,答案就是 0

如果 mod != 0,答案变成了找原数组中的最短连续子数组,使得其数字和除以 P,余数也是 mod


由于是求解连续子数组和的问题,很容易想到使用前缀和。

我们可以扫描一遍整个数组,计算到每个元素的前缀和。

假设当前前缀和除以 P 的余数是 curmod,为了找到一段连续子数组对 P 的余数是 mod,我们需要找到一段前缀和,对 P 的余数是 targetmod。其中 targetmod 的求法是:

如果 curmod >= mod,很简单:targetmod = curmod - mod

如果 curmod < mod,我们需要加上一个 Ptargetmod = 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;
    }
};

觉得有帮助请点赞哇!

❌