和为k的子数组

和为 K 的子数组

问题重述:

给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

问题分析:

一般看到数组中的连续子数组求和,我们会想到使用前缀和

解法:

前缀和

解题:

代码:
public static int subarraySum(int[] nums, int k) {
        // 定义一个前缀和数组
        int[] preNums = new int[nums.length+1];
        // 前缀和数组的第一个值为0
        preNums[0] = 0;
        // 为前缀和数组赋值
        for(int i = 1; i < preNums.length;i++){
            preNums[i] = preNums[i-1] + nums[i-1];
        }
        int count = 0;
        for(int left = 0;left < preNums.length;left++){
            for(int right = left+1;right < preNums.length;right++){
                if(preNums[right] - preNums[left] == k){
                    count += 1;
                }
            }
        }
        return count;
    }
	public static int subarraySum1(int[] nums,int k){
		int count = 0,pre = 0;
		Map<Integer,Integer> map = new HashMap<Integer,Integer>();
		map.put(0, 1);
		for(int num : nums) {
			pre += num;
			if(map.containsKey(pre - k)) {
				count += map.get(pre-k);
			}
			map.put(pre,map.getOrDefault(pre, 0)+1);
			
		}
		return count;
	}

代码解析:

前面一个方法是单纯的前缀和方法,时间复杂度为O(N),我们定义了一个前缀和数组,其中的每一个数组元素都对应了原来数组的前n项和,接下来我们遍历前缀和数组。我们先固定数组的左边界,让左边不动,然后数组的右边节不断向右扩张,扩张一个,就将当前的值和k进行对比,如果相同,则count+1,不相同则右边界扩张。如果右边界到达了数组的末尾,将左边界右移一位,右边界回到左边界的起始位置,重新开始,知道左边界遍历到数组的末尾,最后得到的count就是和为k的子数组个数

第二个方法是对前缀和方法的优化,使用哈希表来帮助我们简化了求子数组和的过程。我们在遍历数组的时候,每一次都记录数组的前缀和,哈希表中以前缀和为key,前缀和出现的次数作为value存放数据。因为pre[j]-pre[i] = k,所以pre[i] = pre[j]-k,所以我们可以用当前前缀和-k的值代表此时有一个子数组的和为k,因此我们只需要判断哈希表中有没有pre[j]-k对应的数据就可以了,每一次遍历一个结点都要对哈希表进行更新。

总结:

前缀和的适用范围:在数组中,当我们要求连续数组的和的时候,我们就要考虑使用前缀和。

posted @   foldn  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示