LeetCode 二分算法 范围内整数的最大得分

时间:2024-11-09 08:15:14

范围内整数的最大得分

给你一个整数数组 start 和一个整数 d,代表 n 个区间 [start[i], start[i] + d]。
你需要选择 n 个整数,其中第 i 个整数必须属于第 i 个区间。所选整数的 得分 定义为所选整数两两之间的 最小 绝对差。
返回所选整数的 最大可能得分 。
示例 1:
输入: start = [6,0,3], d = 2
输出: 4
解释:
可以选择整数 8, 0 和 4 获得最大可能得分,得分为 min(|8 - 0|, |8 - 4|, |0 - 4|),等于 4。
示例 2:
输入: start = [2,6,13,13], d = 5
输出: 5
解释:
可以选择整数 2, 7, 13 和 18 获得最大可能得分,得分为 min(|2 - 7|, |2 - 13|, |2 - 18|, |7 - 13|, |7 - 18|, |13 - 18|),等于 5。
提示:
2 <= start.length <= 105
0 <= start[i] <= 109
0 <= d <= 109

题解

我们可以看到,题目要求得分的最大值

而得分是所有两数差的最小值

也就是最小值的最大值,所以我们对得分采用二分算法,二分得到最大的得分

首先确定二分的边界,也就是得分的边界

最小值是 0 ,因为绝对值大于等于0

最大值是数组 start 中的最大值 + d

接着,对于一个得分 m ,我们要如何进行二分

  • 假设一个当前某一个区间的数为 x0
  • 要使得分为 m ,则下一个数 x1至少为 x0 + m
  • 假如 x0 + m 在下一个数的区间[ x1 , x1+d ]内,则此区间内的数取为 x0 + m
  • else if x0 + m > x1 + d 说明不可能让得分为 m ,需要将右边界置为 m-1
  • else if x0 + m < x1 则下一个区间的数取为 x1
  • 如果数组 start 中的所有数据都可以得到得分 m
  • 那么 m就是一个可能的值,记录下来,将左边界置为m+1

上述步骤中,对于下一个数的取值,永远是大于等于前一个数,这样就可以避免绝对值的两端讨论

但是要使这样的操作是正确的,前提是数组中的数据是升序的,这样下一个数的取值才是永远大于前一个数的

所以首先对数组 start 进行排序

对于第一个数 x0 的取值,因为要获得m得分,下一个数的取值要 >= x0+m,所以 x0 越小,下一个数的取值就越有可能满足条件,所以 x0 就是 strat[ 0 ]

代码如下↓

int maxPossibleScore(int* start, int startSize, int d) {
    int cmp(void const* a,void const* b)
    {
        return *(int*)a - *(int*)b;
    }
    qsort(start,startSize,sizeof(int),cmp);
    long long l=0,r=start[startSize-1]+d;
    int res=0;
    while(l<=r)
    {
        long long m=(l+r)/2;
        long long x=start[0];
        int f=1;
        for(int i=1;i<startSize;i++)
        {
            x+=m;
            if(x>start[i]+d)
            {
                r=m-1;
                f=0;
                break;
            }
            else
            {
                if(x<start[i])
                {
                    x=start[i];
                }
            }
        }
        if(f)
        {
            res=m;
            l=m+1;
        }
    }
    return res;
}