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;
    }
};
posted @ 2021-10-17 21:11  ChrisNg  阅读(80)  评论(0编辑  收藏  举报