【leetcode】560. 和为 K 的子数组

题目链接:和为K的子数组

题目描述:

给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数。

题目思路:

方法一:暴力解法O(n^2) 超时

var subarraySum = function(nums, k) {
    const length=nums.length;
    let num=0;
    for(let i=0;i<length;i++){
        let sum=nums[i];
        if(sum===k)
            num++;
        for(let j=i+1;j<length;j++){
            sum+=nums[j];
            if(sum===k)
                num++;
        }
    }
    return num;
};

方法二:前缀和O(n^2) 超时

var subarraySum = function(nums, k) {
    const length=nums.length;
    let num=0;
    const dp=new Array(length+1);
    dp[0]=0;
    // 数组前缀和
    for(let i=0;i<length;i++){
        dp[i+1]=dp[i]+nums[i];
    }
    for(let i=1;i<=length;i++){
        for(let j=i;j<=length;j++){
            if(dp[j]-dp[i-1]===k)
                num++;
        }
    }
    return num;
};

方法三:前缀和+哈希表优化 时间O(n) 空间O(n)

分析:求连续和为k的子数组的个数,即求出以每一个nums[i]为区间结尾的和为k的子数组的个数之和。

设前缀数组prev,prev[i]为[0,i]的元素之和 ,

若0<=j<=i,prev[i]-prev[j]===k,则从[j+1,i]区间的子数组和为k。

所以要求连续和为k的子数组的个数,就要求出prev[i]-prev[j]===k的个数,即求出prev[i]-k===prev[j]的个数。其中0<=j<=i。

所以要求出以i为区间结尾的且子数组和为k的子数组的个数,需要找出其左边前缀和为prev[i]-k的前缀和个数。

定义一个map,key为数组的前缀和,value为该前缀和出现的次数,从左往右遍历,对于每一个prev[i],prev[i]-k出现的次数,就是以i为区间结尾的且和为k的子数组的个数。

由于prev[i]=prev[i-1]+nums[i],只和前面一个元素有关,所以不需要用数组,只用一个prev变量表示前缀和即可。

// 前缀和+哈希表优化
var subarraySum = function(nums, k) {
    const map=new Map();
    let count=0,prev=0;
    map.set(0,1);
    for (const item of nums) {
        prev+=item;
        if(map.has(prev-k)){
            count+=map.get(prev-k);
        }
        if(map.has(prev)){
            map.set(prev,map.get(prev)+1);
        }else
            map.set(prev,1);
    }
    return count;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值