29 剑指offer--堆 数组--最小的K个数

mac2024-04-04  35

                                        最小的K个数

题目

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

思路

最简单的方法就是先排序,然后在遍历输出最小的K个数,方法简单粗暴。

代码

import java.util.ArrayList; public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { ArrayList<Integer> returnList = new ArrayList<>(); if(input == null || input.length ==0 || k <1 || k>input.length){ return returnList; } int[] ks = new int[k]; for(int i =0;i<k;i++){ ks[i] = input[i]; } for(int i =(ks.length-1)/2;i>=0;i--){ toHeap(ks,i,ks.length); } for(int i =k;i<input.length;i++){ if(input[i] < ks[0]){ ks[0] = input[i]; toHeap(ks,0,ks.length); } } for(int i =0;i<k;i++){ returnList.add(ks[i]); } return returnList; } public void toHeap(int [] input,int start,int end){ int index = start; int left = index*2+1; int right = index*2+2; while(left < end && input[left] > input[index]){ index = left; } while(right < end && input[right] > input[index]){ index = right; } if(index !=start){ int temp = input[start]; input[start] = input[index]; input[index] = temp; toHeap(input,index,end); } } }

代码1 找一个放置的空间

public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { List<Integer> list = new ArrayList<Integer>(); if (k>input.length || k==0) { return (ArrayList)list; } for (int i = 0; i < k; i++) { list.add(input[i]); } for (int i = k; i < input.length; i++) { Collections.sort(list); if(input[i] < list.get(k-1)){ list.set(k-1, input[i]); } } return (ArrayList)list; }

代码2 PriorityQueue

public static void main(String[] args) { int [] input = {4,5,1,6,2,7,3,8}; System.out.println(GetLeastNumbers_Solution(input,4)); } public static ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { ArrayList<Integer> list = new ArrayList<>(); if (input == null || k <= 0 || k > input.length || input.length==0) { return list; } PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2){ return o2 - o1; } }); for(int i=0; i<input.length; i++){ if(pq.isEmpty() || pq.size()<k) { pq.add(input[i]); } else{ if(input[i]<pq.peek()){ pq.poll(); pq.add(input[i]); } } } while(!pq.isEmpty()){ list.add(pq.poll()); } return list; }

代码3

import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Arrays; public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) { ArrayList<Integer> list = new ArrayList<>(); if (input == null || k <= 0 || k > input.length) { return list; } int[] kArray = Arrays.copyOfRange(input, 0, k); //1.构建大顶堆 for(int i=kArray.length / 2 - 1;i>=0;i--){ //从第一个非叶子节点开始,下次第二个,依次调整构建大根堆 adjustHeap(kArray,i,kArray.length); } //2.依次来判断,有小于堆顶的那就替换掉继续调整一个堆 for (int i = k; i < input.length; i++) { if (input[i] < kArray[0]) { kArray[0] = input[i]; adjustHeap(kArray, 0, kArray.length); } } //最后把堆里的元素读出来 for (int i = kArray.length - 1; i >= 0; i--) { list.add(kArray[i]); } return list; } public static void adjustHeap(int []arr,int i,int length){ //从i节点开始调整, int temp = arr[i];//先取出当前元素i for(int k = i*2+1;k<length;k = k*2+1){ //从i结点的左子结点开始,也就是2i+1处开始 if(k+1<length && arr[k]<arr[k+1]){ //如果左子结点小于右子结点,k指向右子结点 k++; } if(arr[k] >temp){ //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换) arr[i] = arr[k]; i = k; }else{ break; } } arr[i] = temp; //将temp值放到最终的位置 }

代码4

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

O(n*logk)

import java.util.ArrayList; /** * @Auther: liuhaidong * Data: 2020/1/14 0014、14:05 * Description: * @version: 1.0 */ public class Test17 { public static void main(String[] args) { int [] arr ={4,5,1,6,2,7,3,8}; System.out.println(GetLeastNumbers_Solution(arr,4)); } public static ArrayList<Integer> GetLeastNumbers_Solution(int [] ins, int k) { if(ins == null || k>ins.length){ return new ArrayList<>(); } int[] ks = new int[k]; // 最先遍历的k个数放入数组中 o(k) for (int i = 0; i < k; i++) { ks[i] = ins[i]; } int half = (ks.length-1) / 2; for (int i = half; i >= 0; i--) { maxHeap(ks, ks.length, i); } //n-k个数和前面和k中最大数比较 for (int i =k; i < ins.length; i++) { //如果堆顶大于n-k中数,则交换位置 if(ks[0]>ins[i]){ ks[0]=ins[i]; //调整堆,堆顶被替换了,加入被替换的值非常小,会一直下沉到叶子节点. maxHeap(ks,ks.length,0); } } ArrayList<Integer> lists = new ArrayList<>(); // 输出最小的K个数 for (int i = 0; i < k; i++) { lists.add(ks[i]); } return lists; } public static void maxHeap(int[] array, int heapSize, int index) { int left = index * 2 + 1; int right = index * 2 + 2; int largest = index; //判断有没有左节点,如若有则比较替换largest if (left < heapSize && array[left] > array[largest]) { largest = left; } //判断有没有右节点,如若有则largest和右节点比较,注意largest有可能是left也有可能是index if (right < heapSize && array[right] > array[largest]) { largest = right; } if (index != largest) { int temp = array[index]; array[index] = array[largest]; array[largest] = temp; //被替换的largest节点所在的堆,需要重新调整,使小值/大值一直下沉 maxHeap(array, heapSize, largest); } } }

关键代码

int[] ks = new int[k]; // 最先遍历的k个数放入数组中 o(k) for (int i = 0; i < k; i++) { ks[i] = ins[i]; } int half = (ks.length-1) / 2; for (int i = half; i >= 0; i--) { maxHeap(ks, ks.length, i); }

这个代码相当于构建堆

参考网站 bilibili.com/video/av47196993/ 

最新回复(0)