leetcode 和为目标值且不重叠的非空子数组的最大数目[哈希表+贪心算法]
1546. 和为目标值且不重叠的非空子数组的最大数目[哈希表+贪心算法]
难度:中等
给你一个数组 nums 和一个整数 target 。
请你返回 非空不重叠 子数组的最大数目,且每个子数组中数字和都为 target 。
示例 1:
输入:nums = [1,1,1,1,1], target = 2
输出:2
解释:总共有 2 个不重叠子数组(加粗数字表示) [1,1,1,1,1] ,它们的和为目标值 2 。
示例 2:
输入:nums = [-1,3,5,1,4,2,-9], target = 6
输出:2
解释:总共有 3 个子数组和为 6 。
([5,1], [4,2], [3,5,1,4,2,-9]) 但只有前 2 个是不重叠的。
示例 3:
输入:nums = [-2,6,6,3,5,4,1,2,8], target = 10
输出:3
示例 4:
输入:nums = [0,0,0], target = 0
输出:3
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
0 <= target <= 10^6
因为我们是要求解子区间的和等于target,直接算肯定是不好算的。但是我在看leetcode官方答案的时候,发现了一个结论,如果我们一个子数组的右端确定了,那么左端就确定了。我们可以逐步进行求和处理。在这里我们使用哈希表unordered_set来储存sum。
实际上搜索过程就是用下面的代码实现实现的。
假设搜索成功,那么\(\textrm{sum}'\)就是在哈希表中存在的差。
\[\textrm{sum}-\textrm{target}=\textrm{sum}'
\]
变化以下
\[\textrm{target}=\textrm{sum}-\textrm{sum}'
\]
意味着有一个元素加前面的某一段和等于target,搜索成功,count自增。但是我们需要注意,不能重叠。因此在第一个循环末尾要进行i++
。这样就保证了不重叠。
我们在具体实现就是从左到右遍历一次。直至找到所有的count。因为在遍历的过程中,我们是可能找到局部最优解的,就是找到子数组和等于target。贪心算法就是我们从局部出发,每一步都找到当前的最优解,最后就可以找到最优解(注意在有些问题中,最优解并不是全局最优解。我觉得这种算法和梯度下降法类似。)
if(s.find(sum-target)!=s.end()){
//查找成功
count++;
break;
}
else{
//查找失败,指针右移继续查找
s.insert(sum);
i++;
}
实现代码
class Solution {
public:
int maxNonOverlapping(vector<int>& nums, int target) {
//利用哈希表
//为了保证没有重叠,我们每一次每一轮都要使用新的哈希表
int sum = 0;
int count = 0;
int i = 0;
int size = nums.size();
while(i<size){
unordered_set<int> s = {0};
sum = 0;
//查找
while(i<size){
sum += nums[i];
if(s.find(sum-target)!=s.end()){
//查找成功
count++;
break;
}
else{
//查找失败,指针右移继续查找
s.insert(sum);
i++;
}
}
i++;
}
return count;
}
};