560 和为k的子数组
解题思路:
\qquad
一开始看到连续非空序列,会想到是不是可以用双指针表示一个区间,然后通过一次遍历找出所有可能的区间,但看到元素的取值区间就知道行不通,这个方法仅适用于数组元素大于等于0的情况。若数字是负数,随着区间长度的增加,其和的值不一定会增加,因而只能把所有的区间遍历一遍去找。
\qquad 巧妙的解法在于转化,将连续序列的和,转化成两个序列和的值之差(感觉有点dp的影子)。
\qquad
对于每个位置i
,记录[0, i]
区间内所有元素的和,因此sum[j+1,i] = sum[0,i] - sum[0,j]
。这样,题目从一个区间问题,变成了一个a - b = k
这种类似两数之和的问题了,妙啊。这些元素之和以及个数可以通过map记录,实现
O
(
1
)
O(1)
O(1)查找。而且由于j < i
,而在一次遍历过程中,map只能存储当前位置之前的累加和,所以一举两得,只用一次遍历即可解决。
int subarraySum(vector<int>& nums, int k) {
int ans = 0, pre = 0;
unordered_map<int,int> m;
m[0] = 1;
for(auto n : nums)
{
pre += n;
if(m.find(pre - k) != m.end())
{
ans += m[pre - k];
}
m[pre]++;
}
return ans;
}