[LeetCode]560. 和为K的子数组

题目

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

示例 1 :

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

说明 :

  1. 数组的长度为 [1, 20,000]。
  2. 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。

解题思路

解法一:暴力法

枚举左右边界,计算区间内的和满足k的区间个数。

复杂度分析:
时间复杂度:O(n^2),其中 n 为数组的长度。枚举子数组开头和结尾需要 O(n^2)的时间,其中求和需要 O(1) 的时间复杂度,因此总时间复杂度为 O(n^2)。
空间复杂度:O(1)。只需要常数空间存放若干变量。

解法二:前缀和 + 哈希表优化

定义数组 sum[j] 为[0…j]所有元素的和,那么sum[j]可以由sum[j-1]递推而来,sum[j]=sum[j-1]+nums[j],则[i…j]这个子数组的和可以表示为 s[i…j]=sum[j]-sum[i-1],要使这个子数组的和为k,也就是s[i…j]=sum[j]-sum[i-1]=k,即sum[i-1]=sum[j]-k。当获得sum[j]的值的时候,先去检查曾经是否有sum[j]-k也就是sum[i-1]出现过。如果出现过,就说明存在子数组s[i…j]之和为k的情况。
这可以借助哈希表保存累加和sum及出现的次数。若累加和sum−k在哈希表中存在,则说明存在连续子数组之和为k。由于 sum[i] 的计算只与前一项的答案有关,因此我们可以不用建立 sum 数组,直接用 sum 变量来记录 sum[i−1] 的答案即可。
具体做法是:
1)初始化哈希表hash={0:1},表示累加和为0,出现了1次。初始化累加和sum=0。初始化结果res=0。
2)遍历数组:
2.1)更新累加和sum+=nums[i];
2.2)若sum-k存在于hash中,说明存在连续子数组之和为k。则令res+=hash[sum-k],表示sum-k出现几次,就存在几种子数组之和为k。
2.3)若sum存在于hash中,将其出现次数加一。若不存在,将其加入hash。
3)返回res。

复杂度分析:
时间复杂度:O(n),其中 n 为数组的长度。我们遍历数组的时间复杂度为 O(n),中间利用哈希表查询删除的复杂度均为 O(1),因此总时间复杂度为 O(n)。
空间复杂度:O(n),其中 n 为数组的长度。哈希表在最坏情况下可能有 n 个不同的键值,因此需要 O(n) 的空间复杂度。

代码

解法一:暴力法(Python超时,Java通过)

Python代码如下:

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        res = 0
        for i in range(len(nums)):
            s = 0
            for j in range(i, len(nums)):
                s += nums[j]
                if s == k:
                    res += 1
        return res

Java代码如下:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int n = nums.length;
        int res = 0;
        for(int i=0; i<n; i++){
            int s = 0;
            for(int j=i; j<n; j++){
                s += nums[j];
                if(s==k){
                    res++;
                }
            }
        }
        return res;
    }
}

解法二:前缀和 + 哈希表优化

Python代码如下:

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        hash_dic = {0:1}
        res = 0
        s = 0
        for i in range(len(nums)):
            s += nums[i]
            if s-k in hash_dic:
                res += hash_dic[s-k]
            if s in hash_dic:
                hash_dic[s] += 1
            else:
                hash_dic[s] = 1
        return res

Java代码如下:

class Solution {
    public int subarraySum(int[] nums, int k) {
        HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>();
        hash.put(0, 1);
        int sum = 0;
        int res = 0;
        for(int i=0; i<nums.length; i++){
            sum += nums[i];
            if(hash.containsKey(sum-k)){
                res += hash.get(sum-k);
            }
            // // 写法一
            // if(hash.containsKey(sum)){
            //     hash.put(sum, hash.get(sum)+1);
            // }else{
            //     hash.put(sum, 1);
            // }
            // 写法二
            hash.put(sum, hash.getOrDefault(sum, 0) + 1);
        }
        return res;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值