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在哈希表中存在时更新最大长度
- 只保存前缀和第一次出现的位置以获得最长子数组
具体步骤:
- 初始化哈希表和前缀和变量
- 遍历数组,累加前缀和
- 检查当前前缀和是否等于k
- 检查前缀和减k是否存在于哈希表中
- 更新最大长度
- 如果当前前缀和不在哈希表中则添加
时间复杂度:O(n)
空间复杂度:O(n)
图解思路
前缀和计算过程表
索引 | 数组值 | 前缀和 | 目标差值(sum-k) | 最大长度 | 说明 |
---|---|---|---|---|---|
0 | 1 | 1 | -2 | 0 | 初始状态 |
1 | -1 | 0 | -3 | 0 | 更新前缀和 |
2 | 5 | 5 | 2 | 0 | 更新前缀和 |
3 | -2 | 3 | 0 | 4 | 找到和为k的子数组 |
4 | 3 | 6 | 3 | 4 | 维持最大长度 |
哈希表状态表
前缀和 | 首次出现位置 | 更新时机 |
---|---|---|
0 | -1 | 初始化 |
1 | 0 | 遍历位置0 |
0 | 1 | 遍历位置1 |
5 | 2 | 遍历位置2 |
3 | 3 | 遍历位置3 |
6 | 4 | 遍历位置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 ms | 45.2 MB | 实现简洁,性能适中 |
Python | 84 ms | 17.8 MB | 代码最简洁 |
C++ | 68 ms | 36.5 MB | 性能最优 |
代码亮点
- 🎯 使用前缀和优化子数组和计算
- 💡 巧妙运用哈希表存储历史信息
- 🔍 只保存前缀和第一次出现的位置
- 🎨 处理整数溢出的情况
常见错误分析
- 🚫 没有考虑整数溢出问题
- 🚫 忘记初始化前缀和为0的情况
- 🚫 重复更新哈希表导致长度不是最大
- 🚫 没有正确处理负数的情况
解法对比
解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
---|---|---|---|---|
前缀和+哈希表 | O(n) | O(n) | 时间效率高 | 需要额外空间 |
暴力枚举 | O(n^2) | O(1) | 空间效率高 | 时间复杂度高 |
相关题目
📖 系列导航
🔥 算法专题合集 - 查看完整合集
📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新至第325题。
💬 互动交流
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
- 👍 点个赞,让更多人看到这篇文章
- 📁 收藏文章,方便后续查阅复习
- 🔔 关注作者,获取更多高质量算法题解
- 💭 评论区留言,分享你的解题思路或提出疑问
你的支持是我持续分享的动力!
💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!