和为k的子数组

和为k的子数组的总个数

前缀和+哈希表

  • 定义pre[i]为[0...i]里所有数的和,则pre[i] = pre[i-1] + nums[i]
  • [j...i]这个子数组的和为k等价于:pre[i] - pre[j-1] = k,可以转化为pre[j-1] = pre[i] - k
  • 当计算以i为结尾的和为k的连续子数组的时候只要统计有多少个前缀和为pre[i]-k的pre[j]即可
  • 建立hash表map.以和(pre)为键,出现的次数为value,从左往右更新map,就可以在O(1)的时间内得到以i为结尾的答案mp[pre[i]-k]
  • 最后的答案就为所有下标结尾和为k的子数组个数之和。
  • 值得注意的是:因为pre[i]只和pre[i-1]有关,因此可以不用真正建立pre数组,直接用pre变量来记录pre[i-1]即可。

代码实现

class Solution {
    public int subarraySum(int[] nums, int k) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        int pre = 0;
        int ans = 0;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);//错误:少了这行代码
        for(int i = 0; i < nums.length; i++){
            pre += nums[i];
            int target = pre - k;
            ans += map.getOrDefault(target, 0);
            map.put(pre, map.getOrDefault(pre, 0) + 1);
        }
        return ans;
    }
}

未排序数组中累加和未给定值k的最长子数组长度

解题思路

  • 和上一题类似,只是map集合中存的不再是前缀和出现的个数,而是前缀和最早出现的位置下标。

实现代码

import java.util.*;


public class Solution {
    /**
     * max length of the subarray sum = k
     * @param arr int整型一维数组 the array
     * @param k int整型 target
     * @return int整型
     */
    private int res = Integer.MIN_VALUE;
    public int maxlenEqualK (int[] arr, int k) {
        // write code here
       //利用前缀和+哈希表实现
        if(arr == null || arr.length == 0){
            return Integer.MIN_VALUE;
        }
        int pre = 0;
        //利用map存储,key为前缀和, value为最早的那个下标
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, -1);
        for(int i = 0; i < arr.length; i++){
            pre += arr[i];
            //target为待查找的前缀和
            int target = pre - k;
            if(map.containsKey(target)){
                int start = map.get(target);
                res = Math.max(res, i - start);
            }
            else{
                //在不包含的情况下,只有当集合中之前不存在对应前缀和的情况下,才放入
               if(!map.containsKey(pre)){
                   map.put(pre, i);
               }
            }
        }
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值