桶排序、计数排序、基数排序

本文介绍了桶排序、计数排序和基数排序三种非基于比较的排序算法,它们的时间复杂度为O(N),且排序稳定。在特定场景下,如数组元素范围限定,这些排序方法能高效工作。例如,对于范围在0~60的数组,可以通过构建词频数组实现排序。在面试中,有时会要求在O(N)的时间复杂度内找到排序后相邻元素的最大差值,可通过设置桶并寻找相邻非空桶之间的差值来解决。
摘要由CSDN通过智能技术生成

1、桶排序、计数排序、基数排序不是基于比较的排序,与被排序的样本的实际数据状况很有关系,所以实际中并不经常使用。计数排序是桶排序的一个实际应用。
2、时间复杂度O(N),额外空间复杂度O(N)
3、稳定的排序

例子:给你一个数组,数组中的所有数的范围是0~60的,把这个数组排好序。
做法:生成一个长度为61的(词频)数组,初始化数组为{0,0,…,0}。然后遍历原数组,遇到一个数的时候,在该数对应词频数组下标的位置++,表示词频加1。比如初始数组为{2,1,3,7,1,0,5,4,6,6,1,1,2,0}对应的词频数组是{2,4,2,1,1,1,2,1},这样就可以通过词频数组去重建整个数组为{0,0,1,1,1,1,2,2,3,4,5,6,6,7}。时间复杂度为O(N)。

面试常考问题:给定一个数组,求如果排序之后,相邻两个数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。
做法:
1)准备桶。若有N个数,就准备N+1个桶。0号桶,1号桶,…,N号桶。每个桶只记录出现在这个桶的数的最小值和最大值以及这个同是否进来过数。
2)从1号桶开始,如果他是空桶,则直接跳下一个数,如果它是非空桶,则找前一个非空桶,对于后面的任何一个非空桶,要找这个非空桶左边离它最近的非空桶,他左边离它最近的非空桶的最大值max和它当前这个非空桶的最小值min,算一下差值,我们要求的最大差值一定在这些答案中间是最大的。

注意:我们设计空桶的分析方式就是为了否定最大差值来自一个桶内部的可能性,但我们没说过最大差值一定来自于空桶两侧的非空桶。

public class Test{
	public static int maxGap(int[] arr){
		if(arr==null||arr.length<2) {
			return 0;
		}

		int min=Integer.MAX_VALUE;
		int max=Integer.MIN_VALUE;
		for(int i=0;i<arr.length;i++) {//遍历数组找出数组的最大值和最小值
			min=Math.min(min, arr[i]);
			max=Math.max(max, arr[i]);
		}
		if(max==min) {//数组只有一种数的情况
			return 0;
		}
		//下面3个数组表示0~N号桶的3个信息
		boolean[] hasNum=new boolean[arr.length+1];
		int[] maxs=new int[arr.length+1];
		int[] mins=new int[arr.length+1];
		
		int bid=0;
		for(int i=0;i<arr.length;i++) {
			bid=bucket(arr[i],arr.length,min,max);//确定当前数属于几号桶
			//数字进入桶之后,相应的最大值,最小值,hasNum标志等都要相应变化
			mins[bid]=hasNum[bid]?Math.min(mins[bid], arr[i]):arr[i];
			maxs[bid]=hasNum[bid]?Math.max(maxs[bid], arr[i]):arr[i];
			hasNum[bid]=true;
		}
		int res=0;//全局最大差值
		int lastMax=maxs[0];//初始化lastMax为0号桶的最大值
		int i=1;
		for(;i<=arr.length;i++) {//从1号桶开始找到每一个非空桶和左边离它最近的非空桶,用当前桶最小值-前一个非空桶的最大值=res
			if(hasNum[i]) {//若桶不为空
				res=Math.max(res, mins[i]-lastMax);//比较当前res与当前桶最小值与前一个非空桶的最大值的差值,取最大值赋值给res
				lastMax=maxs[i];//当前非空桶的最大值赋值给lastMax,继续进行下一轮遍历
			}
		}
		return res;
	}
	//确定当前数属于几号桶
	public static int bucket(long num,long len,long min,long max) {
		return (int)((num-min)*len/(max-min));
	}
	
	public static void main(String[] args) {
		int[] arr= {6,3,4,3,1,3,9,5};
		System.out.println(maxGap(arr));
		
	}
		
}

输出:3


import java.util.Arrays;

public class Test{
	public static int comparator(int[] arr) {
		if(arr==null||arr.length<2)
			return 0;
		Arrays.sort(arr);
		int gap=Integer.MIN_VALUE;
		for(int i=1;i<arr.length;i++) {
			gap=Math.max(arr[i]-arr[i-1], gap);
		}
		return gap;
	}
	
	public static void main(String[] args) {
		int[] arr= {6,3,4,3,1,3,9,5};
		System.out.println(comparator(arr));
		
	}
		
}

输出:3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值