1. 题⽬链接:560.和为K的⼦数组
2. 题⽬描述:
4. 解法⼀(将前缀和存在哈希表中):
算法思路:
设i 为数组中的任意位置,⽤sum[i] 表⽰[0, i] 区间内所有元素的和。 想知道有多少个「以i 为结尾的和为k 的⼦数组」,就要找到有多少个起始位置为x1, x2, x3... 使得[x, i] 区间内的所有元素的和为k 。那么[0, x] 区间内的和是不是就是 sum[i] - k 了。于是问题就变成:
◦ 找到在[0, i - 1] 区间内,有多少前缀和等于sum[i] - k 的即可。 我们不⽤真的初始化⼀个前缀和数组,因为我们只关⼼在i 位置之前,有多少个前缀和等于 sum[i] - k 。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种 前缀和出现的次数。
C++算法代码:
class Solution
{
public:
int subarraySum(vector<int>& nums, int k)
{
//哈希表存各个点的前缀和,出现的次数
unordered_map<int,int>hash;
//此处哈希表用于计算nums-k(差值)的值
hash[0]=1; //故当差值为0时说明有一个结果
int sum=0; //计算前缀和
int ret=0; //累加答案的种类数
for(int i=0;i<nums.size();i++)
{
//计算前缀和
sum+=nums[i];
//累计计算各个区间内的答案个数
//判断这个点的前面有几个点的前缀和等于差值,这样之后的所有数就会是一个答案
if(hash.count(sum-k))
{
//因为区间一直在变,所以要+=
ret+=hash[sum-k];
}
//记录各个点的前缀和
hash[sum]++;
}
return ret;
}
};
Java算法代码:
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
hash.put(0, 1);
int sum = 0, ret = 0;
for (int x : nums)
{
sum += x; // 计算当前位置的前缀和
ret += hash.getOrDefault(sum - k, 0); // 统计结果
hash.put(sum, hash.getOrDefault(sum, 0) + 1); // 把当前的前缀和丢到哈
希表⾥⾯
}
return ret;
}
}