【Leetcode】2555. 两个线段获得的最多奖品_2081
题目
2555. 两个线段获得的最多奖品
在 X轴 上有一些奖品。给你一个整数数组 prizePositions ,它按照 非递减 顺序排列,其中 prizePositions[i] 是第 i 件奖品的位置。数轴上一个位置可能会有多件奖品.再给你一个整数 k 。
你可以同时选择两个端点为整数的线段。每个线段的长度都必须是 k 。你可以获得位置在任一线段上的所有奖品(包括线段的两个端点)。注意,两个线段可能会有相交。
- 比方说 k = 2 ,你可以选择线段 [1, 3] 和 [2, 4] ,你可以获得满足 1 <= prizePositions[i] <= 3 或者 2 <= prizePositions[i] <= 4 的所有奖品 i 。
请你返回在选择两个最优线段的前提下,可以获得的 最多 奖品数目。
- \(1<=prizePositions.length<=10^5\)
思路
题目很长,但是其实就是找到两个可以存在交叉的区间,每个区间的长度不超过k的限制下,两个区间能够覆盖的数组中最多的元素个数。
首先可以想到的是,如果题目要求的是找到一个区间长度不超过k所能覆盖的最多元素个数,那么此时就是使用滑动窗口了,每次移动右端点的同时,去除左边超过区间长度的元素即可。由于数组已经是非递减的了,所以循环的过程中窗口的左右边界就是可以直接进行判断的区间的左右边界。
进而考虑找到这么两个区间,可以明确的是,两个区间存在重叠的情况总是被两个区间不重叠所包含的。也就是说,我们不需要去关心重叠和不重叠两种情况。重叠的时候也总是需要把重复的元素去除多次考虑,因此可以只关心不重叠的情况。
仍然是考虑使用滑动窗口,当窗口右移动的时候,以当前右边界结尾的最大窗口大小就是当前窗口的大小。而窗口的左边界之前的所有元素为结尾的最大窗口大小可以在窗口滑动的过程中进行记录。那么此时就得到了一个以当前元素为右边界的最大窗口和一个不与该窗口重叠的最大窗口,他们的和就是结果。
如果假定最后的结果就是两个重叠窗口呢?此时上述方法还有效吗?
答:有效,如果最后的结果就是重叠的情况,那么此时在滑动过程中,实际上所找到的两个窗口就是完全相邻的情况。也就是存在重叠,只不过重叠的大小未知,因为对于求解的结果而言,也确实不重要。
class Solution:
def maximizeWin(self, prizePositions: List[int], k: int) -> int:
if k * 2 + 1 >= prizePositions[-1] - prizePositions[0]:
return len(prizePositions)
t = defaultdict(int)
cur = 0
l = 0
lm = 0
ans = 0
for x in prizePositions:
cur+=1
while x-prizePositions[l]>k:
cur-=1
lm = max(lm,t[prizePositions[l]])
l+=1
ans = max(ans, cur+lm)
t[x] = max(t[x],cur)
return ans
可以看到最终的代码是加了一个特判,即如果选取了两个长度为k的区间可以完全的包含整个数组所在的位置,那么此时就可以覆盖所有的元素。

浙公网安备 33010602011771号