1824. 钻石收藏家 题型:双指针 二分

102 阅读2分钟

1824. 钻石收藏家 - AcWing题库

题意解析

题目说所有相差大于k的钻石不能放在一个区间内(把整个数组看为一个区间),也就是让我们把非法钻石从区间内剔除。最后我们的区间内所有钻石的尺寸都是相差小于k的。

此时我们统计一下合法区间内的钻石个数。注意这里指的不是两两钻石相差小于k,而是整个区间内任意两颗钻石的差不能超过k。那么我们可以用双指针维护一段区间,看区间内的所有元素是否合法,非法的话我们就缩短区间,把非法的钻石剔除,如果合法的话我们就扩大区间,继续找更大的合法区间。

样例解析

这是题目给的样例:

image.png

我们将其排个序:

image.png

然后我们用两个指针i,j去维护一段区间,i负责缩小区间,j负责扩大区间:

image.png

此时a[j]-a[i]<=k,满足条件,该区间是合法区间,我们统计一下当前区间中钻石的数量,然后j向右扩大区间,看是否存在一个更大的合法区间;

image.png

直到j=5的时候,我们发现a[j]-a[i]>k,也就是这是一段非法区间,那我们就需要缩小区间:

image.png

此时还是不满足条件,接着缩小:

image.png

此时我们发现满足条件了,那么当前区间就是合法的情况,我们统计一下当前区间内的钻石的数量:ji+1j-i+1

双指针解法

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int a[N];
int ans;
int main()
{
    int n,k;cin>>n>>k;
    
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
    
    for(int i=1,j=1;j<=n;j++)
    {
      while(i<j&&a[j]-a[i]>k) //不满足条件就缩小区间 
      i++;
      
      ans=max(ans,j-i+1);
    }
    cout<<ans<<endl;
 return 0;   
}

二分法

同样的我们发现这个特性也特别适合二分,因为求最大区间长度,所以适合第二个板子:

image.png

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n,k;
int ans;
bool check(int l,int r)
{
    if(a[r]-a[l]<=k)return true;

return false;    
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
        
    for(int i=1;i<=n;i++)
    {
        int l=i,r=n;
        while(l<r)
        {
            int mid=l+r+1>>1;
            
            if(check(i,mid))l=mid;  //区间合法,扩大区间,找是否用更大长度区间
            else r=mid-1;           //当前区间非法,缩小区间
        }
        ans=max(ans,r-i+1);
    }
    cout<<ans<<endl;
    return 0;
}