[M滑动窗口] lc2555. 两个线段获得的最多奖品(滑动窗口+同向双指针+代码技巧)

1. 题目来源

链接:2555. 两个线段获得的最多奖品

2. 题目解析

挺有意思的一道题目,同向双指针+简单dp 的思想。

思路:

  • 题目要求枚举两个线段,其实可以想到经典题目「两数之和」。
  • 我们可以枚举靠右的线段位置,然后由于靠右的线段已经枚举了,所以靠左的线段的信息也是知道的。
  • 可以枚举,靠右的线段右端点 r,然后左端点即为 l = r - k + 1 所在位置。这个简单使用滑动窗口维护 l 位置即可。
  • 此时,我们仅需知道 左侧,取得线段最大值是多少即可得到当前构成的奖品总数。sum = pri[l] + r - l + 1;
  • 而 pri 数组又可以在枚举 r 的同时进行维护
  • pri[i] 指的是 在 i 位置前,不包括 i 点的情况下,满足条件的线段获取到的奖品最大值。即 [0, i) 位置下的合法线段获取到的最大值。
  • 简单依照 dp 的思想,pri[r] = max(pri[r - 1], r-l+1) 即可。
    • 当前 r 点所能构成的最大奖品即为 r-l+1。
    • r 点前所能构成的最大奖品为 pri[r-1]
    • 故 r 点所能构成的最大奖品即为两数的最大值。

代码实现小细节:

  • 这里的 pri[r] 类似前缀和数组一样,r 的所处位置是开区间,是不能被取到的。
  • 故当数组长度为 n 时,针对 pri 预处理数组来讲,可以将长度开到 n+1。
  • 这样的好处是:当枚举到 r 点时,它的奖品应该由 [0, l) 部分 + r-l+1 构成。
  • 此时,就可以直接写成 pri[l] + r - l + 1 而不用写成 pri[l-1] + r - l + 1 。即不用考虑 0 这个特殊情况。
  • 同时,转移方程下标也同时向前推进 1,变为 pri[r+1]=max(pri[r], r-l+1)
  • 这样会让代码简洁很多,并且由同样效果。

本题是个很套路的题目,且是一个经典题目,乍一看有贪心做法,实际上很难证明贪心做法的正确性,也没必要去证明了。


  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

代码:

class Solution {
public:
    int maximizeWin(vector<int>& prizePositions, int k) {
        int n = prizePositions.size();
        int pre[n + 1]; memset(pre, 0, sizeof(pre));
        int res = 0;
        for (int l = 0, r = 0; r < n; r ++ ) {
            while (prizePositions[r] - prizePositions[l] > k) l ++ ;
            res = max(res, pre[l] + r - l + 1);
            pre[r + 1] = max(pre[r], r - l + 1);
        }

        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值