1546. 和为目标值且不重叠的非空子数组的最大数目
大约 3 分钟
---
1546. 和为目标值且不重叠的非空子数组的最大数目
- 标签:贪心、数组、哈希表、前缀和
- 难度:中等
题目链接
题目大意
描述:给定一个数组 和一个整数 。
要求:返回可以找到的互不重叠的非空子数组的最大数目,每个子数组的和都等于 。
说明:
- 。
- 。
- 。
示例:
- 示例 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 个是不重叠的。解题思路
思路 1:贪心 + 前缀和 + 哈希表
1. 核心思想
为了得到最大数量的不重叠子数组,应该每次找到和等于 的子数组后,立即选择它(贪心),然后继续向后找。因为在当前最早结束的位置选择一个子数组,能为后面的子数组留出最多空间。
具体地,使用哈希表记录前缀和的最新位置。遍历数组,维护当前前缀和 。如果 在哈希表中,说明存在一个和为 的子数组。选择它,然后重置哈希表(仅保留 位置),继续向后。
2. 贪心正确性证明
这是一个区间调度问题。每个和为 的子数组可以看作一个区间。要最大化不重叠区间的数量,按右端点最早进行贪心选择是最优的。
我们维护 集合(记录当前轮次的前缀和),一旦找到 ,说明找到了以当前位置为右端点的最短满足条件的子数组。立即选择它,然后清空 重新开始,等价于选择了右端点最早的区间。
3. 具体步骤
第 1 步:,。
第 2 步:,。
第 3 步:遍历每个 :
- 。
- 如果 :,清空 ,,。
- 否则:。
4. 举例说明
以 为例:
- :,,。
- :,,,重置 ,。
- :,。
- :,,,重置。
- :,。
最终 。
以 为例:
- 子数组 和为 ,不是 。
- :,。
- :,。
- :,。
- :,。
- :,( 是 时的前缀和),说明 和为 ,,重置。
最终 。
思路 1:代码
class Solution:
def maxNonOverlapping(self, nums: List[int], target: int) -> int:
seen = set()
seen.add(0)
cur = 0
ans = 0
for x in nums:
cur += x
if cur - target in seen:
ans += 1
seen = set()
seen.add(0)
cur = 0
else:
seen.add(cur)
return ans思路 1:复杂度分析
- 时间复杂度:,一次遍历。
- 空间复杂度:,哈希表。