最大k个数——各种解法

思路二,三转自:https://blog.csdn.net/yangchangji/article/details/60141016

思路一:快排序法,  用二分的快排,找第k大的位置,找到后k左边得数就是结果,(如果二分的中点在k左边,继续在右侧找k的位置,反之在左侧二分)时间复杂度O(nlgk)

import java.util.ArrayList;
 
class Solution 
{
	public void solve(ArrayList<Integer> res,int[] input,int left,int right,int k)
	{
		int t;
		int i=left;
		int j=right;
		int temp=input[left];
		while(i<j)
		{
			i=i+1;
			while(input[i]<temp&&i<right)
				i++;
			while(input[j]>temp&&j>left)
				j--;
			if(i<j)
			{
				t=input[i];
				input[i]=input[j];
				input[j]=t;
			}
		}
		if(j>=left&&i<=right)
		{
			t=input[left];
			input[left]=input[j];
			input[j]=t;
		}
		if(j+1==k)
		{
			for(int u=0;u<k;u++)
				res.add(input[u]);
			return;
		}
		if(j+1>k&&j>left)
			solve(res,input,left,j-1,k);
		if(j+1<k&&i <right)
			solve(res,input,j+1,right,k);
	}
    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k)
    {
    	ArrayList<Integer> res=new ArrayList<Integer>();
    	if(input.length==k)
    		for(int i=0;i<input.length;i++)
    			res.add(input[i]);
    	else if(input.length!=0)
    		solve(res,input,0,input.length-1,k);
    	return res;
    	
    }
}

   

思路二:局部替换法   假设前k个数就是整个数组中最小的,找出最大的数和k+1比较,如果比k+1大就和K=1互换位置,然后再将k数组中的最大数找出,在进行比较,知道数组末尾.时间复杂度O(nk)

                         

[plain] 
view plain
 copy

  1. /**  
  2.  * 思路 二   
  3.  * 把整个数组分为k和n-k 2部分,找出最小的K个数的过程其实就是把最大的数放到n-k部分的过程,每次比较都把最大的数交换到n-k的部分里面。  
  4.  * 1.把最先遍历到的k个数赋值到大小为k的数组2中   
  5.  * 2.在数组2中找出最大元素max,时间复杂度是o(k),因为如果  
  6.  * 3.在数组1中遍历剩下的n-k个数,和max比较,如果小于max则交换位置,重复2的过程 o(k)+(n-k)o(k)=n*o(k)  
  7.  **/  
  8. public static void scheme1(int[] ins, int k) {  
  9.     int[] ks = new int[k];  
  10.     // 最先遍历的k个数放入数组中 o(k)  
  11.     for (int i = 0; i < k; i++) {  
  12.         ks[i] = ins[i];  
  13.     }  
  14.     for (int i = k; i < ins.length; i++) {  
  15.         if (getMax(ks) > ins[i]) {  
  16.             ks[0] = ins[i];  
  17.         }  
  18.     }  
  19.     // 输出最小的K个数  
  20.     for (int i = 0; i < k; i++) {  
  21.         System.out.print(ks[i] + ” “);  
  22.     }  
  23. }  
  24.     public static int getMax(int[] arr) {  
  25.     // 选择一个基数,分别于数组中其他元素比较,始终保持基数对应的指针是最大值  
  26.     int radix = 0;  
  27.     for (int i = 0; i < arr.length; i++) {  
  28.         // 如果sub小于旁边值则交互位置  
  29.         if (arr[radix] < arr[i]) {  
  30.             int temp = arr[radix];  
  31.             arr[radix] = arr[i];  
  32.             arr[i] = temp;  
  33.         }  
  34.     }  
  35.     return arr[radix];  
  36. }  

思路三: 对思路二中找最大数的优化,用前K个数建立最大堆,每次用堆顶元素和n-k中各个元素比较,如果堆顶元素较大,则互换位置,然后调整堆,使之重新成为最大堆。时间复杂度

O(n*logk)

    

[plain] 
view plain
 copy

  1. public static void headSort(int[] array) {  
  2.         if (array == null || array.length <= 1) {  
  3.             return;  
  4.         }  
  5.         buildMaxHeap(array);  
  6.     }  
  7. /**  
  8.  * 创建堆  
  9.  *   
  10.  * */  
  11.     public static void buildMaxHeap(int[] array) {  
  12.         if (array == null || array.length <= 1) {  
  13.             return;  
  14.         }  
  15.         //从最后的一个非叶子节点向上开始排,避免迭代没有意义的叶子节点  
  16.         int half = (array.length-1) / 2;    
  17.         for (int i = half; i >= 0; i–) {  
  18.             maxHeap(array, array.length, i);  
  19.         }  
  20.     }  
  21. /**  
  22.  *   
  23.  * 调整堆(沉降法)  
  24.  * logn  
  25.  * */  
  26.     public static void maxHeap(int[] array, int heapSize, int index) {  
  27.         int left = index * 2 + 1;  
  28.         int right = index * 2 + 2;  
  29.   
  30.         int largest = index;  
  31.         //判断有没有左节点,如若有则比较替换largest  
  32.         if (left < heapSize && array[left] > array[largest]) {  
  33.             largest = left;  
  34.         }  
  35.         //判断有没有右节点,如若有则largest和右节点比较,注意largest有可能是left也有可能是index  
  36.         if (right < heapSize && array[right] > array[largest]) {  
  37.             largest = right;  
  38.         }  
  39.   
  40.         if (index != largest) {  
  41.             int temp = array[index];  
  42.             array[index] = array[largest];  
  43.             array[largest] = temp;  
  44.             //被替换的largest节点所在的堆,需要重新调整,使小值/大值一直下沉  
  45.             maxHeap(array, heapSize, largest);  
  46.         }  
  47.   
  48.     }  
  49.       
  50.     /**  
  51.      * 思路二 最大堆法  
  52.      * 利用树形的特点保存前面比较的结果,可以减少比较次数s  
  53.      */  
  54.     public static void scheme2(int[] ins, int k) {  
  55.         int[] ks = new int[k];  
  56.         // 最先遍历的k个数放入数组中 o(k)  
  57.         for (int i = 0; i < k; i++) {  
  58.             ks[i] = ins[i];  
  59.         }  
  60.         //构建前k个数的最大堆  
  61.         headSort(ks);  
  62.         //n-k个数和前面和k中最大数比较  
  63.         for (int i =k; i < ins.length; i++) {  
  64.             //如果堆顶大于n-k中数,则交换位置  
  65.             if(ks[0]>ins[i]){  
  66.                 ks[0]=ins[i];  
  67.                 //调整堆,堆顶被替换了,加入被替换的值非常小,会一直下沉到叶子节点.  
  68.                 maxHeap(ks,ks.length,0);  
  69.             }  
  70.               
  71.         }  
  72.         // 输出最小的K个数  
  73.         for (int i = 0; i < k; i++) {  
  74.             System.out.print(ks[i] + ” “);  
  75.         }  
  76.     }  

测试:

public static void main(String[] args) {
        // 前key个最小的数
        int k = 6;
        int[] ins = new int[] { 8, 6, 10,9,7, 2 ,1,20,13};
        //scheme1(ins, k);
        scheme2(ins, k);
    }

点赞