描述:给定一个整数数组和一个整数k,找到数组中和为k的连续子数组的个数。
Description: Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.
Example:
Input: nums = [1, 1, 1], k = 3; output: 1
Constrains:
- The length of the array is in range of [1, 20000]
- The range of number in array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7]。
Tips: PreFix-Sum, Hash-Map,
思路:连续子数组的和与连续子数组的和仍然是连续子数组;
方法1:采用枚举方法, PreFix-Sum[i]表示前i个数组元素和,遍历[0, i-1]之间的j元素,存在PreFix-Sum[i] - PreFix-Sum[j] == k,在表示存在一个和为k的子数组。
改进:如果提前计算出全部的PreFix-Sum,则需要额外的空间O(n)和时间O(n); 这里采用在for(j in [0, i-1])的时候开始从后往前计算累加和sum, 如果sum == k表明存在一个和为k的子数组。
int subarraySum(vector<int> &nums, int k)
{
int nums_size = nums.size();
int counts = 0;
for(int i = 0; i<nums_size; ++i)
{
int sum = 0;
for(int j=i; j>=0; --j)
{
sum += nums[j]; // 从后往前加
if (sum == k)
counts++;
}
}
return counts;
}
时间复杂度:O(n^2), 空间复杂度O(1)
方法2:从方法1中可以看到,每个i都需要重新开始从j处从尾到头的计算sum, 这样存在重复计算;而且针对PreFix-Sum, i从前往后遍历的过程中,如果在i出存在sum - k存在过(采用一个哈希表记录
原理示意图
int subarraySum(vector<int> &nums, int k)
{
int nums_size = nums.size();
unordered_map<int, int> hash_map; // <key, count>
hash_map[0] = 1; // 如果sum == k, 表明整个子数组满足要求
int sum = 0;
int counts = 0;
for(auto & num : nums) // C++11
{
sum += num;
counts += hash_map[sum - k]; // 存在和为sum-k的子数组
++hash_map[sum];
}
return counts;
}
时间复杂度:O(n), 空间复杂度:O(n)hash_map