【LeetCode刷题】NO.3

299 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

1.题目

560. 和为 K 的子数组 给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数。 示例 1:

输入: nums = [1,1,1], k = 2
输出: 2

示例 2:

输入: nums = [1,2,3], k = 3
输出: 2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

二、思路分析:

看到题目的要求,返回数组和为k的连续子数组,数组和、连续子数组两个关键信息让我们想到了解决该问题的最佳方案:利用前缀和框架进行求解。常规的前缀和求解即先把数组中每一项的前缀和记录在前缀和数组中,然后在通过for循环寻找符合条件的数组nums[j,i-1]元素和并记录下来,但是常规的前缀和解法可能时间复杂度很高会超出时间限制,所以我们需要改进算法。

//起始算法超出时间限制 
for(let i=0 ; i<n ; i++){ 
//记录数组的每一项前缀和 preSum[i+1] = preSum[i] + nums[i] 
} 
for(let i=1 ; i<=n ; i++){
for(let j=0 ; j<i ; j++){
if(preSum[i] - preSum[j] == k){ res++ } 
    } 
}

我们从题目要求中得知我们只需要得到元素和为k的次数,所以我们可以在得到前缀和的同时记录这个前缀和出现的次数,当得到每个前缀和的值后,每次减去要求的元素和K寻找那个减后的值出现的次数即可,每次进行累加,到最后一项完成寻找的时候我们就找到了所有元素和为k时出现的次数。

三、代码:

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var subarraySum = function(nums, k) {
    let tempsum = 0
    let res = 0
    let n = nums.length
    let resMap = new Map()
    resMap.set(0,1)
    for(let i=0 ; i<n ; i++){
        tempsum += nums[i]
        if(resMap.has(tempsum-k)){
            res += resMap.get(tempsum-k)
        }
        if(resMap.has(tempsum)){
            resMap.set(tempsum,resMap.get(tempsum)+1)
        }else{
            resMap.set(tempsum,1)
        }
    }
    return res
};

时间复杂度:O(n)

四、总结:

根据题目要求想出最优解的思路,这种元素和问题一般都是采用前缀和思路进行求解,而所有的元素和问题都可以用前缀和框架求解,学会了前缀和的思想我们就可以举一反三了!