LeetCode第 560 题:和为K的子数组(C++)

560. 和为K的子数组 - 力扣(LeetCode)

在这里插入图片描述

注意要考虑负数

直接dfs超时:

class Solution {
public:
    int res = 0;
    int subarraySum(vector<int>& nums, int k) {
        for(int i = 0; i < nums.size(); ++i)
            dfs(nums, k, i, nums[i]);
        return res;
    }
    void dfs(vector<int>& nums, int k, int idx, int sum){
        if(k == sum){
            ++res;
        }
        if(idx == nums.size()-1)  return;
        dfs(nums, k, idx+1, sum+nums[idx+1]);
    }
};

两处for循环暴力枚举(效率一般),先固定右边界i,遍历左边界j:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int res = 0;
        for(int i = 0; i < nums.size(); ++i){
            int sum = 0;
            //考虑以i为结尾的连续子数组,那么开头可能是i之前的每一个数,组要枚举
            for(int j = i; j >= 0; --j){//注意这儿如果从前往后的话就会有很多重复计算
                sum += nums[j];
                if(sum == k)    ++res;
            }
        }
        return res;
    }
};

当然也可以先固定左边界,枚举右边界:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int res = 0, n = nums.size();
        for(int i = 0; i < n; ++i){
            int sum = 0;
            //i为左边界
            for(int j = i; j < n; ++j){//枚举右边界
                sum += nums[j];
                if(sum == k)    ++res;
            }
        }
        return res;
    }
};

计算连续的和,想到了前缀和+哈希表的思路:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int res = 0, sum = 0;
        unordered_map<int, int> m;//<前缀和,出现次数>
        m[0] = 1;//初始值,前缀和为0,代表没有元素的时候
        for(const auto &num : nums){
            sum += num;//前缀和
            if(m.count(sum-k))  res += m[sum-k];
            ++m[sum];
        }
        return res;
    }
};

换种写法,可能更好理解:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int res = 0;
        vector<int> presum(nums.size()+1, 0);
        //前缀和,第一个为0,代表没有元素
        for(int i = 1; i < presum.size(); ++i) presum[i] = presum[i-1] + nums[i-1];
        //for(auto c : presum)   cout << c << " ";
        unordered_map<int, int> m;//<前缀和,出现次数>
        for(const auto &v : presum){
            if(m.count(v-k))   res += m[v-k];
            ++m[v];
        }
        return res;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值