题目描述
给定一个未排序的数列,找到此数列在已排序状态下的两个相邻值的最大差值,少于两个值时返回0。例如:给定数列 [1,3,2,0,1,6,8] 则 最大差值为3。注意:请尽量使用时间复杂度为O(n)的方案。
输入描述
第一行输入单个整数N作为数列的大小,第二行输入所有数列中的元素M,共N个。0 < N <= 1000000, 0 < M < 2100000000。
输出描述
数列的最大差值
解题思路
这道题使用二分排序后AC了,但是题目要求使用时间复杂度O(N),而一般的排序算法很难达到这个时间复杂度(可以使用桶排序)。之所以使用O(n)的时间复杂度就可以解决这道题,是因为我们不需要通过严格的数据位置信息。
这里的思路是n个数,找出最小minv和maxv,将其划分为n个区间,其中maxv单独一个区间,前面n-1个区间每个区间大小是delta=(maxv-minv)/(n-1),这样就形成了[a,a+delta)形式的区间,而所有相邻数据的差值最大值就是两个区间间的差值(下一个区间的最小值和上一个区间的最大值的差值)最大值,区间内的相邻数的差值是不需要考虑的,原因在于这N个数,第一个数和最后一个数分别放在第一个区间和最后一个区间内,中间的数如果存在有多个数在同一个区间的情况,那么一定至少存在一个区间i内没有数,这样区间i+1和i-1的差值一定大于delta,如果所有的数都单独在一个区间内,那么就直接比较所有区间的差值,因此无论如何我们都不需要考虑区间内相邻数的差值情况。
实现代码
#include <iostream>
#define NN 2100000000
#include <vector>
using namespace std;
int main(){
int n,i,maxv,minv;
cin>>n;
vector<int> data(n,0);
maxv=0,minv=NN;
for(i=0;i<n;i++){
cin>>data[i];
if(maxv<data[i]) maxv=data[i];
if(minv>data[i]) minv=data[i];
}
int delta=(maxv-minv)/(n-1);
if(n==2||delta==0) {
cout<<0<<endl;
return 0;
}
vector<int> bucketMin(n,NN),bucketMax(n,0);
for(i=0;i<n;i++){
int index=(data[i]-minv)/delta;
if(bucketMin[index]>data[i]) bucketMin[index]=data[i];
if(bucketMax[index]<data[i]) bucketMax[index]=data[i];
}
int last_max=bucketMax[0];
int max_delta=0;
for(i=1;i<n;i++){
if(bucketMin[i]!=NN&&bucketMin[i]-last_max>max_delta)
max_delta=bucketMin[i]-last_max;
if(bucketMax[i]!=0)
last_max=bucketMax[i];
}
cout<<max_delta<<endl;
return 0;
}