这一题开始以为是sliding window,后来发现,因为有负数,sum不具有单调性,没有办法用slidng window找出optimal solution。
如果考虑brute force的做法,即枚举两个端点i,j, 计算[i,...,j]的和是否等于k。计算区间和可以通过前缀和预处理O(1)得出。
但是这一题的要求是是否等于k,而不是最大值或者最小值。所以如果我们知道前缀和presum[j],只要找到 i such that presum[i]=presum[j]-k,就可以得到区间的左端点。这种通过presum找端点可以通过map实现。
map把presum的值映射到一个sorted index vector,这样枚举右端点j,找到对应的presum[i],选择对应的i最小的一个即可。
另外,由于presum[j]-presum[i]对应区间[i+1,...,j],所以i=0的区间需要特判一下。
class Solution {
public:
int maxSubArrayLen(vector<int>& nums, int k) {
map<int,vector<int>>mp;
vector<int>presum(nums.size());
int ans=0;
// cout<<nums.size()<<endl;
for(int i=0;i<nums.size();i++)
{
if(i==0)
{
presum[i]=nums[0];
}
else
{
presum[i]=presum[i-1]+nums[i];
}
if(mp.find(presum[i])==mp.end())
{
mp[presum[i]]=vector<int>();
}
mp[presum[i]].push_back(i);
// cout<<presum[i]<<endl;
}
// for(auto item=mp.begin();item!=mp.end();item++)
// {
// sort(item->second.begin(),item->second.end(),[](int a,int b)->bool{
// return a>b;
// });
// }
for(auto item=mp.begin();item!=mp.end();item++)
{
int tmp=item->first;
// if(tmp<k)
// {
// continue;
// }
if(tmp==k)
{
ans=max(ans,item->second[item->second.size()-1]+1);
continue;
}
int next=tmp-k;
int ed=item->second[item->second.size()-1];
if(mp.find(next)==mp.end())
{
continue;
}
int st=mp[next][0];
// cout<<tmp<<" "<<st<<" "<<ed<<endl;
if(st<ed)
{
ans=max(ans,ed-st);
}
}
return ans;
int left=0;
int right=0;
int sum=0;
// not all are positive integers, so cannot use sliding window.
// negative -> no monotone
while(right<nums.size())
{
sum+=nums[right];
// cout<<left<<" "<<right<<" "<<sum<<endl;
while(sum>k)
{
sum-=nums[left];
left++;
}
if(sum==k)
{
ans=max(ans,right-left+1);
}
right++;
}
return ans;
}
};