Maximize Win From Two Segments

Maximize Win From Two Segments

There are some prizes on the X-axis. You are given an integer array prizePositions that is sorted in non-decreasing order, where prizePositions[i] is the position of the ith prize. There could be different prizes at the same position on the line. You are also given an integer k .

You are allowed to select two segments with integer endpoints. The length of each segment must be k . You will collect all prizes whose position falls within at least one of the two selected segments (including the endpoints of the segments). The two selected segments may intersect.

  • For example if k = 2 , you can choose segments [1, 3] and [2, 4] , and you will win any prize i that satisfies 1 <= prizePositions[i] <= 3 or 2 <= prizePositions[i] <= 4 .

Return the maximum number of prizes you can win if you choose the two segments optimally.

Example 1:

Input: prizePositions = [1,1,2,2,3,3,5], k = 2
Output: 7
Explanation: In this example, you can win all 7 prizes by selecting two segments [1, 3] and [3, 5].

Example 2:

Input: prizePositions = [1,2,3,4], k = 0
Output: 2
Explanation: For this example, one choice for the segments is [3, 3] and [4, 4], and you will be able to get 2 prizes. 

Constraints:

  • 1prizePositions.length105
  • 1prizePositions[i]109
  • 0k109
  • prizePositions is sorted in non-decreasing order.

 

解题思路

  比赛的时候贪心思路搞错了,一直在wa,然后对着个样例看了半天都不知道错了哪里。

  一开始的贪心思路是想着线段的其中一个端点一定要覆盖到礼物,然后右端点取到长度限制,这里的贪心思路还是对的。然后我就理所应当的认为下一条线段的左端点应该从上一条线段的右端点的右边开始(不要重合),这样做的后果是把序列分成了连续的若干段,再对这若干段按照能够取到的礼物数量从大到小排序,最后取排序结果的前两个作为答案。

复制代码
class Solution {
public:
    int maximizeWin(vector<int>& prizePositions, int k) {
        int n = prizePositions.size();
        vector<int> p(1);
        for (int i = 0; i < n; i++) {
            int j = i + 1;
            while (j < n && prizePositions[j] - prizePositions[i] <= k) {
                j++;
            }
            p.push_back(j - i);
            i = j - 1;
        }
        sort(p.begin(), p.end(), greater<int>());
        return p[0] + p[1];
    }
};
wa code
复制代码

  一开始死都没发现不对的地方,后面看了别人的题解才知道这种做法是有问题的。

  首先容易贪心想到线段端的某个端点(这里假设是左端点)如果包含礼物,那么这条线段能够覆盖的礼物会更多。同时选择的两个线段没有相交的情况能够覆盖到的礼物会更多。

  接着我们通过双指针来预处理得到以i为左端点所能够覆盖到的最大礼物数量,得到数组l[i]。再预处理得到以i为右端点所能够覆盖到的最大礼物数量,得到数组r[i]。然后枚举所有i,作为第二条线段的左端点,此时第一条线段的右端点应该选择max1ji1r[j],因此还需要对r数组求前缀最大值。那么这种情况的所能覆盖到的最大礼物数量为l[i]+max1ji1r[j],在枚举的过程中对所有情况取个最大值。

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     int maximizeWin(vector<int>& prizePositions, int k) {
 4         int n = prizePositions.size();
 5         vector<int> l(n + 1), r(n + 1);
 6         for (int i = 1, j = 1; i <= n; i++) {
 7             while (prizePositions[i - 1] - prizePositions[j - 1] > k) { // 右端点
 8                 j++;
 9             }
10             r[i] = i - j + 1;
11         }
12         for (int i = 1; i <= n; i++) {  // 对r数组求前缀最大值
13             r[i] = max(r[i], r[i - 1]);
14         }
15         for (int i = n, j = n; i; i--) {
16             while (prizePositions[j - 1] - prizePositions[i - 1] > k) { // 左端点
17                 j--;
18             }
19             l[i] = j - i + 1;
20         }
21         int ret = 0;
22         for (int i = 1; i <= n; i++) {
23             ret = max(ret, l[i] + r[i - 1]);
24         }
25         return ret;
26     }
27 };
复制代码

 

参考资料

  two pointers & 枚举:https://leetcode.cn/problems/maximize-win-from-two-segments/solution/two-pointers-mei-ju-by-tsreaper-bui2/

posted @   onlyblues  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示