题目链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/
难度:中等
题目描述:给你一个整数数组 nums
和一个整数 k
,请你统计并返回该数组中和为 k
的连续子数组的个数。
思路:仍是前缀和的方法,难点在于优化。
解法一:暴力破解。先计算前缀和数组,然后利用循环从子数组中寻找等于 k
的个数。这个方法时间复杂度
O
(
n
2
)
O(n^2)
O(n2),空间复杂度
O
(
n
)
O(n)
O(n)。并且在 LeetCode 上提交的话是无法通过的,超时。。因此需要进一步优化,优化的核心在于 if (preSum[i] - preSum[j] == k) res++
这句代码上。
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n = nums.size();
preSum.resize(n + 1);
preSum[0] = 0;
for (int i = 1; i <= n; i++)
preSum[i] = preSum[i - 1] + nums[i - 1];
int res = 0;
int s_preSum = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j < i; j++)
if (preSum[i] - preSum[j] == k)
res++;
return res;
}
private:
vector<int> preSum;
};
解法二:hashmap法。将 preSum[i] - preSum[j] == k
进行移项,得到 preSum[i] - k == preSum[j]
,那么利用 hashmap 保存前缀和 和其出现的次数,则可以去掉内层 for 循环,从而将时间复杂度降低至
O
(
n
)
O(n)
O(n)。
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n = nums.size();
unordered_map<int, int> mp;
mp[0] = 1;
int i_preSum = 0;
int res = 0;
for (int i = 0; i < n; i++) {
i_preSum += nums[i];
if (mp.find(i_preSum - k) != mp.end())
res += mp[i_preSum - k];
mp[i_preSum]++;
}
return res;
}
核心代码位于 if (mp.find(i_preSum - k) != mp.end()) res += mp[i_preSum - k];
其实这句代码跟解法一中的 if (preSum[i] - preSum[j] == k) res++
意义一致。
难点:
- 主要在于如何从
if (preSum[i] - preSum[j] == k) res++
入手优化代码,并利用好 hashmap 的特性。