[每日一题]560. 和为 K 的子数组 前缀和加上递归算法

276 阅读3分钟

这是leetcode中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

通过次数171,586提交次数384,350

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/su…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

\

算法表述


/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var subarraySum = function(nums, k) {
    // //列出两条,一个使用保留上界,一个是用来保留下界,如果位于这之间的话,就让结果加一 18点17分
    // var max = new Array(nums.length)
    // var min = new Array(nums.length)
    // var res = 0
    // max.fill(0)
    // min.fill(0)
    // max[0] = nums[0]
    // min[0] = nums[0]
    // if(k == nums[0]) res++
    // for(let i = 1;i < nums.length;i++){
    //     if((nums[i] + max[i - 1]) > nums[i]){
    //         max[i] = nums[i] + max[i - 1]
    //     }else{
    //         max[i] = nums[i]
    //     }
    //     //如果跟之前建立联系小于当前的值,那么的话就让赋值之前的值
    //     if((nums[i] + min[i - 1]) < nums[i]){
    //         min[i] = nums[i] + min[i - 1]
    //     }else{
    //         min[i] = nums[i]
    //     }
    //     if(k <= max[i] && k >= min[i]){
    //         res++
    //         if(k == nums[i]){
    //             res++
    //         }
    //     }        
    //     //遇到了问题就是如果在这个数之前的和为0的话,是需要加上这种结果的 18点29分 而且的话,我这种计算很奇怪,因为我是基于区间的,所以我觉得是有问题的 18点30分
    //     //应该使用递归,就是把每一种情况放进入,是否需要之前之和 18点32分
    // }
    // return res 

    // var res = 0
    // //当前的数,和数组的第几个数
    // var shenru = function(cur_sum,i){
    //     if(!nums[i]) return
    //     if(cur_sum == k){
    //         res++
    //     }
    //     let sum = cur_sum
    //     let index = i
    //     shenru(nums[index+1],index+1)
    //     shenru(nums[index+1]+sum,index+1)
    // }
    // shenru(nums[0],0)
    // return res

//22点34分
//如果能够找到 pre - x 找到的话, 
//看了答案之后,模仿写出来的,利用的是减法,因为单纯的进行遍历的话,会计算量复杂,而通过减法,也就是不用再次进行求出之前的值
// 对于         1 2 3
// 之前的数     0 1 3 6   
// 然后进行map后0 0 2 0 
//map中的key值,表示这个数被使用了几次
//之所以要使用减法是因为,题目要求的是连续的数组,所以用两个连续的数组之和相减就可以得到,这一段对应的数组之和,为多少
//而这种解法的话,就是用到目前位置的数组之和减去目的数(k),通过哈希表查找,是否存在另外一个数组满足要求
//如果满足要求的话,就让它的键对应的值加上1
   //count表示结果的数,per表示这个数之前的数
    let count = 0,pre = 0;
    var map = new Map()
    map.set(0,1)
 		//对num中的每一个数进行遍历
    for(const x of nums){   
        pre += x
        //判断pre减去k的是否存在,如果存在的对应的数,就获取对应的值,然后加上去
        if(map.has(pre - k)){
            count += map.get(pre-k)
        }
        //判断pre是否存在,存在的话,就对map进行放入新的键与值,并让值等于之前的值加上一
        if(map.has(pre)){
            map.set(pre,map.get(pre)+1)
        }else{
          //不存在的话,就放入新的键与值
            map.set(pre,1)
        }
    }
    return count
};

复杂度分析


时间复杂度为:O(n),遍历数组

空间复杂度为:O(n),哈希表处理

最后


这是我2022年分享的「leetcode」第NO.3篇文章。