LeetCode 每日一题 两个线段获得的最多奖品

两个线段获得的最多奖品

在 X轴 上有一些奖品。给你一个整数数组 prizePositions ,它按照 非递减 顺序排列,其中 prizePositions[i] 是第 i 件奖品的位置。数轴上一个位置可能会有多件奖品。再给你一个整数 k 。
你可以同时选择两个端点为整数的线段。每个线段的长度都必须是 k 。你可以获得位置在任一线段上的所有奖品(包括线段的两个端点)。注意,两个线段可能会有相交。
比方说 k = 2 ,你可以选择线段 [1, 3] 和 [2, 4] ,你可以获得满足 1 <= prizePositions[i] <= 3 或者 2 <= prizePositions[i] <= 4 的所有奖品 i 。
请你返回在选择两个最优线段的前提下,可以获得的 最多 奖品数目。
示例 1:
输入:prizePositions = [1,1,2,2,3,3,5], k = 2
输出:7
解释:这个例子中,你可以选择线段 [1, 3] 和 [3, 5] ,获得 7 个奖品。
示例 2:
输入:prizePositions = [1,2,3,4], k = 0
输出:2
解释:这个例子中,一个选择是选择线段 [3, 3] 和 [4, 4] ,获得 2 个奖品。
提示:
1 <= prizePositions.length <= 105
1 <= prizePositions[i] <= 109
0 <= k <= 109
prizePositions 有序非递减。

解题思路

总体的思路是利用双指针,枚举第二条线段(右边那条)然后用数组维护左边能获得的最多的奖品数量

首先定义左指针 l 与右指针 r,初始值均为0,l 与 r 之间(包括端点)就是我们假设的第二条线段

接着创建数组 arr,arr[x]用于记录 prizePositions[x] 左边能获取的最多的奖品

举个例子 数组 prizePositions 为 [1,1,2,2,3,3,5],k=2

arr[4] 的值就为 4,因为 prizePositions[4] 左边能够获取的最多的奖品就是1,1,2,2,数量为4

如果arr数组的值有了,那么此时奖品的最大值 sum 就是 arr[l](第一条线段的最大奖品数)+ r-l+1(第二条线段的奖品数)

然后 for 循环枚举右指针 r,选取最大的sum值就好了

第二条线段的奖品数很好算,就是两个端点 r - l + 1即可,但是因为线段的长度有规定,所以需要满足 prizePositions[r] - prizePositions[l] <= k,为了符合这个条件,在枚举 r 的时候需要利用 while 语句判断是否需要移动左指针 l

重要的是如何计算第一条线段能获取的最多的奖品数量,也就是如何维护 arr 数组

由于我们是枚举右指针 r,所以利用 r 来作为 arr 的下标,接下来只需要知道 arr[r] 如何计算即可

显然,因为 arr[0] 左边没有数值,arr[0] = 0,由于 r 每次都是加一,所以对于左边来说,也就是每次仅仅是多加了一个可选的数值,即增加了一条以新增的数为右端点的线段,因为 arr[r-1] 就是之前的最大值,所以我们只需要判断这条线段的奖品数与 arr[r-1] 的大小即可

写成式子就是 arr[r+1] = max( arr[r], r-l+1)

直接上代码

int maximizeWin(int* prizePositions, int prizePositionsSize, int k) {
    int* arr = (int*)malloc(sizeof(int)*(prizePositionsSize+1));//arr[x]用于存储在prizePositions[x]左边的能获得的最多奖品
    memset(arr,0,sizeof(int)*(prizePositionsSize+1));
    int l=0,r=0;
    int sum=-1;
    for(l=0,r=0;r<prizePositionsSize;r++)//遍历右边,左边的数值用数组arr维护
    {
        while(prizePositions[r]-prizePositions[l]>k)
        {
            l++;
        }
        arr[r+1] = r-l+1>arr[r]?r-l+1:arr[r];//维护数组,r每向右移一次,就判断新的线段与上一位的大小
        sum = sum>r-l+1+arr[l]?sum:r-l+1+arr[l];
    }
    free(arr);
    return sum;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

软行

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值