leetcode [560. 和为K的子数组]

(https://leetcode-cn.com/problems/subarray-sum-equals-k/)

1:暴力法:因为要求的子数组必须是连续的,所以答案肯定是某一大块减去某一小块的结果正好为k,这样就自然而然的想到前缀和,得到前缀和在暴力枚举就行了,算法复杂度O(n2),我的代码卡在了最后一组数据

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> add(n+1,0);
        for(int i = 1; i <= n; i++) {add[i] = add[i-1]+nums[i-1];}    
        int ans = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 0; j < i; j++){
                if(add[i] - add[j] == k) ans++;
                //if(add[i] - add[j] < k) break;
            }
        }
        return ans;
    }
};

2:前缀和加map优化:我们在利用上一个方法的add[i] - add[j] == k,移项可得到add[j] = add[i]-k ,我们发现暴力方法的时间都浪费在找add[j] 上了,所以我们可以利用一个map来记录add[i] 前的所有前缀和,如果在map中能找到add[i]-k ,我们就加上对应的个数

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        map<int,int> M;
        M[0] = 1;
        int ans = 0,cnt = 0;
        for(int i = 0; i < n; i++){
            cnt += nums[i];
            int p = cnt-k;
            if(M.find(p) != M.end()) ans += M[p];
            M[cnt]++;
        }
        return ans;
    }
};

这个值得说的是,这里的是一步一步求得前缀和,不像我的暴力法中一下子把所有前缀和都给求出来了,这样得好处是对于每个i对应得前缀和,此时map里存的是他前面的所有前缀和,这样才能保证其正确性

猜你喜欢

转载自www.cnblogs.com/Beic233/p/12897722.html