这一题观察数据范围和题目可以知道是应用到前缀和加哈希,正常的思路走即可,但关键点就在于如何实现数组的不重叠,我原想的方案是枚举出符合条件的子数组后,记录它的起始位置,新再枚举的子数组不能处于这个区间内,但这样就忽略了这个重复的数组可能要比之前的数组的长度小,如果不保存这个重叠的子数组,去更新最终两个子数组的长度和时一定会出错,而且子数组不定长,可能是在后面枚举的子数组比前面的要长些,总之不管怎样我们都无法实现对重叠的子数组的有效处理。
看题解后我才明白,解决重叠子数组的关键在于我们用一个dp【】表,每一个索引表示在该位置之前的最小的子数组的长度,这样就避免了对重复子数组的讨论,我们不需要关注两个子数组是否重叠,只需要把一个位置的前面的最小的子数组的长度统计出来即可,有可能在该位置之前有两个子数组是重叠的,但那又何妨,我们只需要判断它们谁长度最小,保存到dp表中即可,这样我们一边的枚举新的子数组,一边的更新新的子数组前面的子数组的长度的最小值这其实也是左维护右枚举的一种思想吧。
class Solution {
public:
int sum[100005];
unordered_map<int,int> mp;
int minSumOfLengths(vector<int>& arr, int target) {
int leftmin[100005];
for(int i=0;i<=arr.size();i++)
{
leftmin[i]=INT_MAX;
}
for(int i=0;i<arr.size();i++)
{
sum[i+1]=sum[i]+arr[i];
}
mp[0]=0;
//sum[j+1]-sum[i]=target
int ans=INT_MAX;
for(int j=0;j<arr.size();j++)
{
leftmin[j+1]=leftmin[j];
if(mp.count(sum[j+1]-target))
{
//如果从哈希表中找到该位置之前存在一个子数组,使他满足条件
int start=mp[sum[j+1]-target]+1;
int len=j+1-start+1;
if(start>0)
{
if(leftmin[start-1]!=INT_MAX)
{
ans=min(ans,leftmin[start-1]+len);
}
leftmin[j+1]=min(leftmin[j+1],len);
}
}
mp[sum[j+1]]=j+1;
}
if(ans==INT_MAX)
{
return -1;
}
else
return ans;
}
};
时间复杂度O(n),涉及到了一些动态规划的思想但其实还算好理解的。