题意解析
题目说所有相差大于k的钻石不能放在一个区间内(把整个数组看为一个区间),也就是让我们把非法钻石从区间内剔除。最后我们的区间内所有钻石的尺寸都是相差小于k的。
此时我们统计一下合法区间内的钻石个数。注意这里指的不是两两钻石相差小于k,而是整个区间内任意两颗钻石的差不能超过k。那么我们可以用双指针维护一段区间,看区间内的所有元素是否合法,非法的话我们就缩短区间,把非法的钻石剔除,如果合法的话我们就扩大区间,继续找更大的合法区间。
样例解析
这是题目给的样例:
我们将其排个序:
然后我们用两个指针i,j去维护一段区间,i负责缩小区间,j负责扩大区间:
此时a[j]-a[i]<=k,满足条件,该区间是合法区间,我们统计一下当前区间中钻石的数量,然后j向右扩大区间,看是否存在一个更大的合法区间;
直到j=5的时候,我们发现a[j]-a[i]>k,也就是这是一段非法区间,那我们就需要缩小区间:
此时还是不满足条件,接着缩小:
此时我们发现满足条件了,那么当前区间就是合法的情况,我们统计一下当前区间内的钻石的数量:
双指针解法
#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;
}
二分法
同样的我们发现这个特性也特别适合二分,因为求最大区间长度,所以适合第二个板子:
#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;
}