LeetCode 3 号题:寻找和为 K 的连续子数组的个数
2023-09-25 05:03:07
前言
在 LeetCode 的题海中,3 号题是一道经典的数组和问题,考验了算法和数据结构的基本功。这道题的本质是查找连续子数组,使得其元素之和等于给定的目标值 K。掌握解决这类问题的技巧,对于程序员在解决实际问题时大有裨益。
问题
给你一个整数数组 nums 和一个整数 k,请你统计并返回该数组中和为 k 的连续子数组的个数。
思路分析
对于这道题,我们可以从以下几个方面考虑解决方法:
1. 暴力破解法
最直接的方法是对数组中的所有连续子数组进行求和,如果子数组的和等于 K,则计数加 1。这种方法的时间复杂度为 O(n^2),其中 n 为数组 nums 的长度,因为对于每个元素都需要遍历所有可能的子数组。
2. 前缀和 + 哈希表
为了优化求和过程,我们可以使用前缀和数组。前缀和数组的前缀和 i 存储了数组 nums 从索引 0 到 i 的元素之和。因此,对于索引 i 和 j,子数组 [i, j] 的和可以快速计算为 sum[j] - sum[i-1]。
有了前缀和数组,我们可以使用哈希表来存储前缀和及其出现的次数。当我们遍历前缀和数组时,如果当前前缀和减去 K 的值在哈希表中,则说明找到了一个和为 K 的子数组。同时,我们更新哈希表中前缀和出现的次数。
这种方法的时间复杂度为 O(n),因为我们只遍历了数组 nums 一次。
代码实现
基于上述思路,我们可以用 Python 语言实现如下代码:
def subarray_sum(nums, k):
# 创建前缀和数组
prefix_sums = [0] * len(nums)
prefix_sums[0] = nums[0]
for i in range(1, len(nums)):
prefix_sums[i] = prefix_sums[i-1] + nums[i]
# 创建哈希表
hash_table = {}
# 遍历前缀和数组
count = 0
for i in range(len(nums)):
# 检查当前前缀和减去 K 的值是否存在于哈希表中
if prefix_sums[i] - k in hash_table:
# 如果存在,则累加哈希表中的出现次数
count += hash_table[prefix_sums[i] - k]
# 将当前前缀和及其出现次数添加到哈希表中
if prefix_sums[i] not in hash_table:
hash_table[prefix_sums[i]] = 1
else:
hash_table[prefix_sums[i]] += 1
return count
时间复杂度分析
上述代码的时间复杂度为 O(n),其中 n 为数组 nums 的长度。我们只遍历了数组一次,使用哈希表来存储前缀和及其出现的次数。
空间复杂度分析
上述代码的空间复杂度为 O(n),因为哈希表中最多存储了 n 个前缀和。
补充说明
在实际应用中,这道题还可以使用滑动窗口算法来解决。滑动窗口算法可以优化暴力破解法的求和过程,将时间复杂度降低到 O(n)。
此外,这道题的变体还有很多,例如查找和为 K 的任意子数组的个数、查找和为 K 的最长连续子数组等。这些变体题型都需要灵活运用上述的基本思想来解决。
总结
通过 LeetCode 3 号题,我们学习了如何解决数组和问题。暴力破解法虽然简单易懂,但效率较低。而前缀和 + 哈希表的方法时间复杂度为 O(n),可以有效提高效率。这道题是数组和问题的典型代表,掌握其解法对于后续解决其他相关问题大有裨益。