本文本质上为本人对力扣题解区灵茶山艾符的题解的理解
看题目条件,给定一个非递减数组表示奖品位置,求两条线段所能覆盖的最大奖品数.先将题目简化,假设只有一条线段,就变成的标准的滑动窗口题.在此基础上,我们要解决的就是求出再加一条线段所能覆盖的奖品数.
先看简化的问题,我们用滑动窗口过一遍数组即可,要注意题目给出的数组表示奖品所在位置,而非x轴上每个位置的奖品个数,所以计算线段长度的公式为prizePositions[r] - prizePositions[l].
int l = 0, ans = 0;
for (int r = 0; r < n; r++) {
while (prizePositions[r] - prizePositions[l] > k) {
l++;
}
ans = max(ans, r - l + 1);
}
这样我们就完成了这道题的二分之一,剩下的就是解决如何找到另外一条线段的最大覆盖数,即长度为k的线段所能覆盖的次大奖品数.上面这段代码其实已经求出了在x轴上每个位置所能覆盖的最大奖品数(此位置指线段右端点位置),既然我们找到最大的线段,在这条线段之前的最大不就是次大的线段了吗.
认识到了这一点,问题就迎刃而解啦.我们创建一个数组来存储每个位置的最大覆盖数即可.
int maximizeWin(vector<int>& prizePositions, int k) {
int n = prizePositions.size();
if (2 * k + 1 >= prizePositions[n - 1] - prizePositions[0]) {
return n;
}
vector<int> mx(n + 1);
int l = 0, ans = 0;
for (int r = 0; r < n; r++) {
while (prizePositions[r] - prizePositions[l] > k) {
l++;
}
ans = max(ans, mx[l] + r - l + 1);
mx[r + 1] = max(mx[r], r - l + 1);
}
return ans;
}
需要注意,mx[x]描述的其实是(x - 1)之前的最大奖品数,但在l = 0时会出现负数,所以我们将mx的大小设为(n + 1),即可避免负数的产生.