题目
思路
题目要求解连续子数组的和等于k的个数,首先得明确如何求解连续子数组的和?
可以利用前缀和数组来实现任意两个位置连续的子数组的和!
前缀和数组的含义如下:
如下图所示,假设数组nums的长度为n,则前缀和数组presums的长度为n+1,对于任意位置i,presums[i]=presums[i-1]+nums[i]=nums[0]+…+nums[i-1],一般设定前缀和数组的第一个元素为0。
有了前缀和数组作为辅助数组,那么求解任意任意两个位置的连续的子数组的和就可转换为:nums[i]+…+nums[j]=presums[j+1]-presums[i],时间复杂度只有o(1)。
有了前缀和数组,如何求解本题呢?
-
思路1:i遍历前缀和数组,用j遍历i的前驱区域[0,i-1) ,寻找nums[i]-nums[j]=k的j的数目。
但这种方式最坏情况需要遍历两次数组,时间复杂度为o(n2)。
-
思路2:这里可以参考 leetcode.1 two sum的解法。利用哈希表存储前缀和数组的元素以及出现的次数,对于nums[i]-k,如果哈希表中存在,则直接累加其次数;如果不存在,则将nums[i]元素插入哈希表,需要注意的是,需要判定哈希表中是否存在nums[i]。
由于哈希表查找的时间复杂度为o(1),外循环的时间复杂度为o(n),因此该方法的时间复杂度为o(n)。
题解
思路1
C++
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
if(nums.empty()) return 0;
int n=nums.size();
vector<int> ans(n+1);
ans.push_back(0);
for(int i=0;i<n;i++) ans[i+1]=ans[i]+nums[i];
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<i;j++)
{
if(ans[i]-ans[j]==k) res++;
}
}
return res;
}
};
C++勉强通过!!!
Python
直接超时
class Solution(object):
def subarraySum(self, nums, k):
if not nums: return 0
n=len(nums)
ans=[0]*(n+1)
for i in range(n): ans[i+1]=ans[i]+nums[i]
res=0
for m in range(1,n+1):
for n in range(0,m):
if(ans[m]-ans[n]==k):
res+=1
return res
思路2
C++
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
if(nums.empty()) return 0;
unordered_map<int,int>ans;
ans[0]=1;
int sum_i=0,sum_j=0,res=0;
for(int i=0;i<nums.size();i++)
{
sum_i+=nums[i];
sum_j=sum_i-k;
if(ans.count(sum_j))
{
res+=ans[sum_j];
}
ans[sum_i]++;
}
return res;
}
};
Python:
class Solution(object):
def subarraySum(self, nums, k):
if not nums: return 0
res={}
res[0]=1
sum_i,sum_j,ans=0,0,0
for i in range(len(nums)):
sum_i+=nums[i]
sum_j=sum_i-k
if(sum_j in res):
ans+=res[sum_j]
if sum_i not in res:
res[sum_i]=0
res[sum_i]+=1
return ans
果然python慢点哈!
参考
1.https://leetcode-cn.com/problems/subarray-sum-equals-k/