最小的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/