力扣-560-和为K的子数组

给定一个整数数组和一个整数k你需要找到该数组中和为k的连续的子数组的个数。

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

方法一、前缀和(不优化)
定义pre[i]为[0..i]里所有数的和,即前缀和。you递推关系得到:  
      pre[i] = pre[i-1]+nums[i];

那有了前缀和,我们就能很方便地表示[j..i]这个子数组的和,时间复杂度为O(1),表示如下:
      sum[j..i] = pre[i] - pre[i-1];

那想要找到满足和为k的子数组的个数,实际上就是求:
      if(pre[i] - pre[j-1]==k){ res++; }

我们可以枚举i,找到满足pre[j] = pre[i]-k的j的个数即可,通过上述分析,我们可以得到下述代码:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int len = nums.length;
        int[] pre = new int[len+1];
        
        for(int i = 1; i <= len; i++) {
            if(i==1) {
                pre[i] = nums[i-1];
            }else {
                pre[i] = pre[i-1] + nums[i-1];
            }
        }
        
        int res = 0;
        for(int i=0; i<=len; i++) {
            for(int j=0; j<i; j++) {
                if((pre[i]-pre[j])==k) {
                    res+=1;
                }
            }
        }
        return res;
    }
}

 

方法二、前缀和+HashMap优化

从方法一,我们可以看到,每次枚举i后,我们都要遍历i之前的j,看是否满足:

               pre[j] == pre[i] - k

所以我们可以考虑用Map,(键,值)= (pre[i], 出现的次数)。在从左到右枚举i的过程中,同时更新hashmap,那么以i结尾的答案hashmap[pre[i] - k],就能在O(1)的时间内得到,最后将枚举所有i的结果累加即可,产生最终的答案。

 

需要注意的是,从左往右计算hashmap[pre[i] - k],里面记录的pre[j]的下表范围是0<=j<=i。又因为pre[i]的计算只与前一项的答案有关,因此就不用建立pre[]数组,直接用pre变量记录即可。代码如下:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int ans = 0, presum = 0;
        Map<Integer, Integer> hashmap = new HashMap<Integer, Integer>();
        
        hashmap.put(0, 1);
        
        for(int i=0; i<nums.length; i++) {
            presum+=nums[i];
            if(hashmap.containsKey(presum - k)) {
                ans += hashmap.get(presum-k);
            }
            hashmap.put(presum, hashmap.getOrDefault(presum, 0) + 1);
        }
        return ans;
    }

 

 

 

 

 

 

 



 

posted @ 2020-11-02 11:56  Peterxiazhen  阅读(125)  评论(0编辑  收藏  举报