【每日一题】LeetCode. 560. 和为k的子数组

每日一题,防止痴呆 = =

一、题目大意

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
【每日一题】LeetCode. 560. 和为k的子数组_第1张图片
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k

二、题目思路以及AC代码

我一开始一看这道题,就把DP和暴力的想法给否定了,数组长度 20000,肯定不能n^2的复杂度,当然DP如果可能是n的复杂度是可以考虑的,但我没想到 = =。

然后就是感觉比较常规的思路,要求某区间的和为k,感觉前缀和是可以的。整体思路如下:首先对给定数组求前缀和数组(时间复杂度O(n)),然后在前缀和数组中,原数组区间加和为k的问题就变成了前缀和数组中两个元素差为k的问题,也就是,如果pre[i] = pre[j - 1] + k,那么[j, i],就是原数组中区间加和为k的区间。

有了上面的知识,下面就有两种思路去求解了。第一个是顺着的思路,就是我们对于每一个元素pre[i],找其后面还有多少元素等于pre[i] + k,将所有这些元素的数量相加,即可得到最终结果,时间复杂度是O(n),当然要借助哈希表的帮助。

第二个思路是逆着的思路,就是我们对于每一个元素pre[i],找其前面有多少元素等于pre[i] - k,其实道理和上面一样,只不过这样的话,我们可以将前缀和数组省去,只用一个变量来保存就好了。

下面给出第一种思路的AC代码:

#include 

typedef long long ll;

class Solution {
     
public:
    int subarraySum(vector<int>& nums, int k) {
     
        int n_size = nums.size();

        vector<ll> pre(n_size);
        unordered_map<ll, int> mm;
        pre[0] = nums[0];
        mm[pre[0]] = 1;
        for (int i=1;i<n_size;i++) {
     
            pre[i] = nums[i] + pre[i-1];
            if (mm.find(pre[i]) == mm.end()) {
     
                mm[pre[i]] = 1;
            }
            else {
     
                mm[pre[i]]++;
            }
        }

        int res = 0;
        for (int i=0;i<n_size;i++) {
     
            mm[pre[i]]--;
            if (pre[i] == k) res++;
            if (mm.find(pre[i] + k) != mm.end()) {
     
                res += mm[pre[i] + k];
            }
        }

        return res;
    }   
};

如果有问题,欢迎大家指正!!!

你可能感兴趣的:(每日一题,leetcode,数据结构,算法,哈希表)