阿里云高频编程考题:和为 K 的子数组 (中等)

题目描述

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

子数组是数组中元素的连续非空序列。

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

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

提示:

  • 1 <= nums.length <= 2 * 10^{4}
  • -1000 <= nums[i] <= 1000
  • -10^{7} <= k <= 10^{7}

解题思路

要解决这个问题,我们可以使用前缀和(Prefix Sum)以及哈希表来优化查找和为 k 的子数组的个数。前缀和的基本思想是通过累积数组元素的和,可以快速计算出任意子数组的和。

具体步骤如下:

  1. 前缀和的定义:我们定义 prefixSum[i] 为数组 nums 从第一个元素到第 i 个元素的累积和。即 prefixSum[i] = nums[0] + nums[1] + ... + nums[i]

    目标是找到一个下标对 (i, j),使得 prefixSum[j] - prefixSum[i-1] = k,这里的 i-1prefixSumi 的前一个位置。转换为查找问题就是:prefixSum[j] - k = prefixSum[i-1]
  2. 使用哈希表记录前缀和的出现次数

    我们用一个哈希表 prefixSumCount 来记录每个前缀和出现的次数,键为前缀和,值为该前缀和的出现次数;在遍历数组的过程中,计算当前的前缀和 currentSum,然后检查哈希表中是否存在 currentSum - k。如果存在,则说明在此之前有一个子数组的和为 k,将结果计数加上对应的次数。
  3. 初始化和遍历

    初始化 currentSum 为 0,同时在哈希表中加入 prefixSumCount[0] = 1,表示在开始前有一个空子数组的和为 0;遍历数组,更新 currentSum,并检查 currentSum - k 是否在哈希表中,更新结果计数。最后,更新哈希表 prefixSumCountcurrentSum 的次数。

复杂度分析

  • 时间复杂度:O(n)。其中 n 是数组 nums 的长度。我们只遍历一次数组,每次操作的时间复杂度是 O(1),因此总的时间复杂度是 O(n)。

  • 空间复杂度:O(n)。在最坏的情况下,哈希表 prefixSumCount 需要存储 n 个不同的前缀和,因此空间复杂度是 O(n)。

代码实现

package org.zyf.javabasic.letcode.hot100.substring;

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

/**
 * @program: zyfboot-javabasic
 * @description: 和为 K 的子数组
 * @author: zhangyanfeng
 * @create: 2024-08-21 21:36
 **/
public class SubarraySumSolution {
    public int subarraySum(int[] nums, int k) {
        // 创建一个哈希表记录前缀和出现的次数
        Map<Integer, Integer> prefixSumCount = new HashMap<>();
        // 初始化前缀和为0的情况
        prefixSumCount.put(0, 1);

        int currentSum = 0; // 当前前缀和
        int count = 0; // 和为k的子数组的数量

        // 遍历数组
        for (int num : nums) {
            // 计算当前前缀和
            currentSum += num;

            // 检查是否存在一个前缀和,使得currentSum - k存在于哈希表中
            if (prefixSumCount.containsKey(currentSum - k)) {
                count += prefixSumCount.get(currentSum - k);
            }

            // 更新哈希表中当前前缀和的出现次数
            prefixSumCount.put(currentSum, prefixSumCount.getOrDefault(currentSum, 0) + 1);
        }

        return count; // 返回和为k的子数组的个数
    }

    public static void main(String[] args) {
        SubarraySumSolution solution = new SubarraySumSolution();

        // 测试用例 1
        int[] nums1 = {1, 1, 1};
        int k1 = 2;
        System.out.println(solution.subarraySum(nums1, k1)); // 输出: 2

        // 测试用例 2
        int[] nums2 = {1, 2, 3};
        int k2 = 3;
        System.out.println(solution.subarraySum(nums2, k2)); // 输出: 2
    }
}

具体可参考:https://zyfcodes.blog.csdn.net/article/details/141401712

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值