力扣-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; }
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!