LeetCode 和为K的子数组 前缀和+Hash java

相关题目:

统计【优美子数组】

k倍区间

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

示例 1 :

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

说明 :

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k

思路.1:

1.这题首先想到的是暴力,三重循环,就是时间复杂度有点高,就不写了,
看怎么来优化暴力。我们看的是某段区间里的和是否为K,假设这个区间是
[i~j],按照暴力的做法就是定一个边界然后缩小边界,看看边界内是否有
个区间的和为k。前缀和正好就符合这个条件,sum[j]-sum[i-1]=k,然后我
们就要统计这个区间有多少个,这样的时间复杂度是O(n)22.O(n)2的复杂的也是有点高,如果想要O(n)的时间复杂度,怎么做呢?用
前缀和的做法是这样的
 	    int count=0;
        for(int j=1;j<=length;j++){
            for(int i=1;i<=j;i++){
                if(sum[j]-sum[i-1]==k){
                    count++;
                }
            }
        }
我们要从以i为右边界里找,有多少个以j为左边界的区间使得sum[j]-
sum[i-1]=k,想减掉i这重循环,要从(sum[j]-sum[i-1]=k)这个
等式来看,sum[i-1]=sum[j]-k,这样改等式可以变成(sum[j]-
(sum[j]-k)=k)这样我们就可以把i“变没”,我们只需要找到以j为右
边间的区间里,sum[j]-k出现的次数然后相加,这里用Hashmap不用
数组来保存sum[j]-k出现的次数,因为有它可能是负数;

3.这里要注意的一点是hashmap要有初始值hashmap.put(0, 1),
关于这个我在网上看到了几个很好的理解方法:
3.1因为数组中有些数直接就等于k(特例帮助理解)
3.2这是因为要保持哈希表的定义, key 是当前位置之前的所有元素的和(依然是前缀和),value 是对应的个数。在遍历开始之前,当前位置之前的所有元素为空,可以认为和是 0,对应的个数就为 1
(分别来自liweiwei大佬和Sumail🍒大佬)

在这里插入图片描述
代码

import java.util.HashMap;
import java.util.Map;

public class Solution {

    public int subarraySum(int[] nums, int k) {
   
        
       // key:前缀和,value:key 对应的前缀和的个数
        Map<Integer, Integer> countsum = new HashMap<>();
        // 对于下标为 0 的元素,前缀和为 0,个数为 1
        countsum.put(0, 1);

        int sum = 0;
        int count = 0;
        for (int num : nums) {
            sum += num;
          
            // 先获得前缀和为sum - k 的个数
            if (countsum.containsKey(sum - k)) {
                          
                count += countsum.get(sum - k);
            }

            // 之前出现过值就加1,没出现个值就为1
            countsum.put(sum, countsum.getOrDefault(sum, 0) + 1);
        }
      
        return count;
     }
}

相比于前缀和快了不少
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值