最小的K个数
描述
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0\le k,n \le 100000≤k,n≤10000,数组中每个数的大小0 \le val \le 10000≤val≤1000
要求:空间复杂度 O(n)O(n) ,时间复杂度 O(nlogn)O(nlogn)
//1.冒泡排序,求最小的k个元素
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
if(input.length<k){
return list;
}
for(int i=0;i<k;i++){
for(int j=0;j<input.length-i-1;j++){
if(input[j]<input[j+1]){
int temp=input[j];
input[j]=input[j+1];
input[j+1]=temp;
}
}
list.add(input[input.length-i-1]);
}
return list;
}
}
2.用快速排序的方法进行比较
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
/使用快速排序方法实现
ArrayList<Integer> list=new ArrayList<Integer>();
if(input.length<k||k==0||input.length==0)
return list;
QuickSort(input,0,input.length-1);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void QuickSort(int[] a,int low,int high){
int start=low;
int end =high;
int key =a[low];
while(end>start){
首先从后往前比较,找小的
while(end>start&&a[end]>=key){
end--;
}
if(key>=a[end]){
int temp=a[end];
a[end]=a[start];
a[start]=temp;
}
接着从前往后,找大的
while(end>start&&a[start]<=key){
start++;
}
if(key<=a[start]){
int temp=a[end];
a[end]=a[start];
a[start]=temp;
}
}
if(start>low) QuickSort(a,low,start-1);
if(end<high) QuickSort(a,end+1,high);
}
}
/3.归并排序
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
///首先对于边界条件进行判断
if(input.length<k||k==0||input.length==0){
return list;
}
/接着开始写主程序
int[] copy=new int[input.length];
GuiBing(input,0,input.length-1,copy);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void GuiBing(int[] a,int low,int high,int[] copy){
/首先要定义递归结束的条件
if(low==high){
return;
}
int mid=(low+high)/2;
GuiBing(a,low,mid,copy);
GuiBing(a,mid+1,high,copy);
int i=mid; /定义一个左边数组的指针
int j=high; /定义一个右边数组的指针
int copyNumber=high; 定义copy数组
while(i>=low&&j>mid){
if(a[i]>a[j]){
copy[copyNumber--]=a[i--];
}else{
copy[copyNumber--]=a[j--];
}
}
/如果左边数组有剩余
for(;i>=low;i--){
copy[copyNumber--]=a[i];
}
如果右边数组有剩余
for(;j>mid;j--){
copy[copyNumber--]=a[j];
}
/将copy数组的值赋给array
for(int n=low;n<=high;n++){
a[n]=copy[n];
}
}
}
4插入排序
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
///首先对于边界条件进行判断
if(input.length<k||k==0||input.length==0){
return list;
}
///插入排序
ChaRu(input);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void ChaRu(int[] input){
//插入排序
for(int i=1;i<input.length;i++){
for(int j=i;j>0;j--){
if(input[j]<input[j-1]){
int temp=input[j];
input[j]=input[j-1];
input[j-1]=temp;
}
}
}
}
}
///5选择排序
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
///首先对于边界条件进行判断
if(input.length<k||k==0||input.length==0){
return list;
}
///选择排序
XuanZe(input);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void XuanZe(int[] input){
//选择排序,每次找到最小,找下一位置
for(int i=0;i<input.length;i++){
int minIndex=i;
for(int j=i+1;j<input.length;j++){
if(input[minIndex]>input[j]){
minIndex=j;
}
}
int temp=input[minIndex];
input[minIndex]=input[i];
input[i]=temp;
}
}
}
6.希尔排序
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
///首先对于边界条件进行判断
if(input.length<k||k==0||input.length==0){
return list;
}
///希尔排序
XiEr(input);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void XiEr(int[] array){
//希尔排序,仔细思考算法的过程
int n=array.length;
for(int k=n/2;k>0;k/=2){ /排序的数量
for(int i=k;i<array.length;i++){ /从k为开始,到结束
for(int j=i;j>=k;j-=k){ 不同的k开始,如果不同就交换
if(array[j]<array[j-k]){
int temp=array[j];
array[j]=array[j-k];
array[j-k]=temp;
}
}
}
}
}
}
//7.基数排序
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
///首先对于边界条件进行判断
if(input.length<k||k==0||input.length==0){
return list;
}
///基数排序
JiShu(input);
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
public void JiShu(int[] array){
//首先找到数组中的最大位数d;后边通过d来表示结果
int maxNumber=array[0];
for(int i=1;i<array.length;i++){
if(maxNumber<array[i]){
maxNumber=array[i];
}
}
int d=0;
while(maxNumber%10!=0){
maxNumber=maxNumber/10;
d++;
}
//下面的这一部分是关于 桶排序和 排序结果返回数组array的循环过程
int k=0; /保存每一位排序后的结构用于下一位的排序输入
int n=0;
int length=array.length;
int[][] bucket=new int[10][length]; //排序桶用于保存每次排序后的结果,这一位上排序结果是相同的数字方在同一个桶里
int[] order=new int[10]; //用于保存每个桶里有多少个数字
while(d--!=0){
for(int num:array){ //将数组array里的每个数字放在相应的桶里
int digit=(int)((num/Math.pow(10,n))%10);
bucket[digit][order[digit]]=num;
order[digit]++;
}
///将前一个循环所生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
for(int i=0;i<length;i++){
if(order[i]!=0){ /这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
for(int j=0;j<order[i];j++){
array[k]=bucket[i][j];
k++;
}
}
order[i]=0;将桶里计数器置为0,用于下一轮存位排序结果
}
k=0;
n++;
}
}
}
8.堆排序,构建最大堆
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list=new ArrayList<Integer>();
//对于边界条件进行限制
if(input==null||input.length==0||k>input.length){
return list;
}
//首先将input.length转换成大根堆
for(int i=(k-1)/2;i>=0;i--){
adjustDui(input,i,k-1);
}
for(int i=k;i<input.length;i++){
if(input[0]>input[i]){
input[0]=input[i];
adjustDui(input,0,k-1);
}
}
for(int i=0;i<k;i++){
list.add(input[i]);
}
return list;
}
/这个方法就是针对每一个点进行向下更新
public void adjustDui(int[] input,int start,int end){
int temp=input[start]; /将根节点存储下来
int child=2*start+1; /找到其左孩子
while(child<=end){
if(child+1<end&&input[child+1]>input[child])
child++;
if(input[child]<temp)
break;
input[start]=input[child]; /将孩子结点的值给父节点
start=child; //更新新的根节点
child=2*start+1;
}
input[start]=temp;
}
}