LeetCode第325题_和等于k的最长子数组长度

LeetCode 第325题:和等于k的最长子数组长度

📖 文章摘要

本文详细解析LeetCode第325题"和等于k的最长子数组长度",这是一道前缀和和哈希表的经典问题。文章提供了前缀和+哈希表的解法,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合想要提升前缀和和哈希表应用能力的程序员。

核心知识点: 前缀和、哈希表、子数组
难度等级: 中等
推荐人群: 具有基础算法知识,想要提升数组和哈希表操作能力的程序员

题目描述

给定一个数组 nums 和一个目标值 k,找到和等于 k 的最长连续子数组的长度。如果不存在任意一个符合要求的子数组,则返回 0。

示例

示例 1:

输入: nums = [1, -1, 5, -2, 3], k = 3
输出: 4
解释: 子数组 [1, -1, 5, -2] 和等于 3,且长度最大。

示例 2:

输入: nums = [-2, -1, 2, 1], k = 1
输出: 2
解释: 子数组 [-1, 2] 和等于 1,且长度最大。

提示

  • 1 <= nums.length <= 2 * 10^5
  • -10^4 <= nums[i] <= 10^4
  • -10^9 <= k <= 10^9

解题思路

方法:前缀和 + 哈希表

使用前缀和和哈希表来优化查找过程。

关键点:

  • 计算前缀和数组
  • 使用哈希表存储前缀和第一次出现的位置
  • 当前前缀和减去目标值k在哈希表中存在时更新最大长度
  • 只保存前缀和第一次出现的位置以获得最长子数组

具体步骤:

  1. 初始化哈希表和前缀和变量
  2. 遍历数组,累加前缀和
  3. 检查当前前缀和是否等于k
  4. 检查前缀和减k是否存在于哈希表中
  5. 更新最大长度
  6. 如果当前前缀和不在哈希表中则添加

时间复杂度:O(n)
空间复杂度:O(n)

图解思路

前缀和计算过程表

索引数组值前缀和目标差值(sum-k)最大长度说明
011-20初始状态
1-10-30更新前缀和
25520更新前缀和
3-2304找到和为k的子数组
43634维持最大长度

哈希表状态表

前缀和首次出现位置更新时机
0-1初始化
10遍历位置0
01遍历位置1
52遍历位置2
33遍历位置3
64遍历位置4

代码实现

C# 实现

public class Solution {
    public int MaxSubArrayLen(int[] nums, int k) {
        Dictionary<long, int> dict = new Dictionary<long, int>();
        dict[0] = -1; // 初始化,处理从0开始的子数组
        long sum = 0;
        int maxLen = 0;
        
        for (int i = 0; i < nums.Length; i++) {
            sum += nums[i];
            
            // 检查当前和是否等于k
            if (sum == k) {
                maxLen = i + 1;
            }
            
            // 检查是否存在sum-k的前缀和
            if (dict.ContainsKey(sum - k)) {
                maxLen = Math.Max(maxLen, i - dict[sum - k]);
            }
            
            // 只保存第一次出现的位置
            if (!dict.ContainsKey(sum)) {
                dict[sum] = i;
            }
        }
        
        return maxLen;
    }
}

Python 实现

class Solution:
    def maxSubArrayLen(self, nums: List[int], k: int) -> int:
        prefix_sum = {0: -1}  # 初始化,处理从0开始的子数组
        curr_sum = 0
        max_len = 0
        
        for i, num in enumerate(nums):
            curr_sum += num
            
            # 检查当前和是否等于k
            if curr_sum == k:
                max_len = i + 1
            
            # 检查是否存在curr_sum-k的前缀和
            if curr_sum - k in prefix_sum:
                max_len = max(max_len, i - prefix_sum[curr_sum - k])
            
            # 只保存第一次出现的位置
            if curr_sum not in prefix_sum:
                prefix_sum[curr_sum] = i
        
        return max_len

C++ 实现

class Solution {
public:
    int maxSubArrayLen(vector<int>& nums, int k) {
        unordered_map<long long, int> prefix_sum;
        prefix_sum[0] = -1; // 初始化,处理从0开始的子数组
        long long curr_sum = 0;
        int max_len = 0;
        
        for (int i = 0; i < nums.size(); i++) {
            curr_sum += nums[i];
            
            // 检查当前和是否等于k
            if (curr_sum == k) {
                max_len = i + 1;
            }
            
            // 检查是否存在curr_sum-k的前缀和
            if (prefix_sum.find(curr_sum - k) != prefix_sum.end()) {
                max_len = max(max_len, i - prefix_sum[curr_sum - k]);
            }
            
            // 只保存第一次出现的位置
            if (prefix_sum.find(curr_sum) == prefix_sum.end()) {
                prefix_sum[curr_sum] = i;
            }
        }
        
        return max_len;
    }
};

执行结果

C# 实现

  • 执行用时:124 ms
  • 内存消耗:45.2 MB

Python 实现

  • 执行用时:84 ms
  • 内存消耗:17.8 MB

C++ 实现

  • 执行用时:68 ms
  • 内存消耗:36.5 MB

性能对比

语言执行用时内存消耗特点
C#124 ms45.2 MB实现简洁,性能适中
Python84 ms17.8 MB代码最简洁
C++68 ms36.5 MB性能最优

代码亮点

  1. 🎯 使用前缀和优化子数组和计算
  2. 💡 巧妙运用哈希表存储历史信息
  3. 🔍 只保存前缀和第一次出现的位置
  4. 🎨 处理整数溢出的情况

常见错误分析

  1. 🚫 没有考虑整数溢出问题
  2. 🚫 忘记初始化前缀和为0的情况
  3. 🚫 重复更新哈希表导致长度不是最大
  4. 🚫 没有正确处理负数的情况

解法对比

解法时间复杂度空间复杂度优点缺点
前缀和+哈希表O(n)O(n)时间效率高需要额外空间
暴力枚举O(n^2)O(1)空间效率高时间复杂度高

相关题目


📖 系列导航

🔥 算法专题合集 - 查看完整合集

📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新至第325题。


💬 互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 👍 点个赞,让更多人看到这篇文章
  • 📁 收藏文章,方便后续查阅复习
  • 🔔 关注作者,获取更多高质量算法题解
  • 💭 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值