问题描述:给一个无序的数组,要求在O(n)的时间内求出排完序后相邻两数的最大间距,不许用桶排。
题解:
用分桶法来做。
先求出数组的最大最小值,然后给每个元素分桶。分桶的计算公式为:(cur-min)*n/(max-min)
这样就能保证正好有n+1个桶(从0到n),对于每个桶只维护其最大最小值,以及里面是否有值。
由于n个数放n+1个桶,必然有一个空桶,所以最大间距必然出现在空桶的左右两边。(空桶一定不会是最后一个或者第一个,因为min和max分占两桶)。
import java.util.Scanner;
public class maxgap {
public static int maxGap(int[] num) {
int len = num.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i=0;i<len;i++) {
min = Math.min(min,num[i]);
max = Math.max(max,num[i]);
}
if(min==max)
return 0;
boolean[] vis = new boolean[len+1];
int[] mins = new int[len+1];
int[] maxs = new int[len+1];
int bid = 0;
for(int i=0;i<len;i++) {
bid = bucket(num[i],min,max,len);//如何证明一个桶内的值肯定不会是最大间距的值
mins[bid] = vis[bid]?Math.min(mins[bid], num[i]):num[i];
maxs[bid] = vis[bid]?Math.max(maxs[bid], num[i]):num[i];
vis[bid] = true;
}
int ans = 0;
int lastmax = maxs[0];
for(int i=1;i<=len;i++) {
if(vis[i]) {
ans = Math.max(ans, mins[i]-lastmax);
lastmax = maxs[i];
}
}
return ans;
}
public static int bucket(int cur,int min,int max,int len) {
return (int) ((cur-min)*len/(max-min));
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n;
n = in.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++)
a[i] = in.nextInt();
int ans = maxGap(a);
System.out.println(ans);
}
}