和为K的子数组-leetCode560

本文探讨了在给定数组中寻找和为特定值K的连续子数组个数的有效算法。介绍了四种方法,包括暴力搜索、改进的累加求和、空间优化的累加求和及使用HashMap实现高效查找。通过分析不同方法的时间与空间复杂度,展示了如何从O(n^3)优化至更高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

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

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

说明 :
 	数组的长度为 [1, 20,000]。
 	数组中元素的范围是 [-1000, 1000] ,且整数 <strong>k </strong>的范围是 [-1e7, 1e7]。

1、 第一种方法是找到所有的连续子数组然后计算数组和,和为k则加一。找到所有的连续子数组的时间复杂度是O(n2)O(n^2)O(n2),计算他们的和为O(n)O(n)O(n),所以总时间复杂度为O(n3)O(n^3)O(n3)。在本题里,数组长度n在[1, 20,000]范围内,所以这种方法会超时。

2、 第二种方法与第一种方法前一部分类似,找到所有的连续子数组,但是它计算数组和时,使用一种累加的方法,将第二部分的时间复杂度降为了O(1)O(1)O(1),总时间复杂度为O(n2)O(n^2)O(n2)。在本例中不会超时,我一开始就是使用的这种方法,下面是代码:
class Solution {
    public int subarraySum(int[] nums, int k) {
        int count=0;
        int sum[]=new int [nums.length];
        int s=0;
        for(int i=0;i<nums.length;i++){
            sum[i]=nums[i]+s;
            s=sum[i];
            if(sum[i]==k) ++count;
        }
        for(int i=1;i<nums.length;i++){
            for(int j=i;j<nums.length;j++){
                sum[j]-=nums[i-1];
                if(sum[j]==k) ++count;
            }
        }
        return count;
    }
}

方法2的其中一个缺点是使用了O(n)O(n)O(n)的额外空间,因此方法3在方法2的基础上进行改进,空间复杂度仅为O(1)O(1)O(1)


3、第三种方法是在找连续子数组的时候,计算累加和,在新增加一个数字时,只需在累加和上增加该数字,因此时间复杂度时O(n2)O(n^2)O(n2),空间复杂度为O(1)O(1)O(1)

4、第四种方法是使用HashMap(当时没想到,看的推荐解法,也贴上来,待翻译。。。主要看图)。

The idea behind this approach is as follows: If the cumulative sum(repreesnted by sum[i] for sum upto i^th index) upto two indices is the same, the sum of the elements lying in between those indices is zero. Extending the same thought further, if the cumulative sum upto two indices, say i and j is at a difference of k i.e. if sum[i] - sum[j] = k, the sum of elements lying between indices i and j is k.

Based on these thoughts, we make use of a hashmap mapmap which is used to store the cumulative sum upto all the indices possible along with the number of times the same sum occurs. We store the data in the form: (sum_i, no. of occurences of sum_i). We traverse over the array numsnums and keep on finding the cumulative sum. Every time we encounter a new sum, we make a new entry in the hashmap corresponding to that sum. If the same sum occurs again, we increment the count corresponding to that sum in the hashmap. Further, for every sum encountered, we also determine the number of times the sum sum-k has occured already, since it will determine the number of times a subarray with sum k has occured upto the current index. We increment the countcount by the same amount.

After the complete array has been traversed, the countcount gives the required result.

The animation below depicts the process.
动图挂了,抱歉

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0, sum = 0;
        HashMap < Integer, Integer > map = new HashMap < > ();
        map.put(0, 1);
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            if (map.containsKey(sum - k))
                count += map.get(sum - k);
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }
        return count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值