剑指Offer:最小的K个数Java/Python

1.题目描述

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

2.算法描述

这种类型的题目都可以用排序算法做,只是时间效率有差别。
最推荐的是堆排序,或者说, / k \red{一旦出现了最大/最小的k个,首先想到的是堆。} 堆其实是基于完全二叉树实现的。
堆分最大堆和最小堆。堆也称为优先队列(PriorityQueue)
最大堆:堆中值最大的元素将最先出堆。
最小堆:堆中值最小的元素将最先出堆。
这里用语言自带的堆 和 自己手写堆排序两种方法。

3.代码描述

3.1.Java代码

/*
方法1:基于自带的优先队列,java中的优先队列是基于堆实现的。所有元素进入一个最小堆,然后从最小堆中弹出k个元素就是k个最小的元素。
*/
import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> ans = new ArrayList<>();
        if(input==null || k<=0 || k > input.length)
            return ans;
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for(int e: input){
            pq.offer(e);
        }
        for(int i=0;i<k;i++){
            int e = pq.poll();
            ans.add(e);
        }
        return ans;
    }
}
/*
方法1:基于自带的优先队列,java中的优先队列是基于堆实现的。只用一个容量为k个最大堆,因为是找最小的k个元素,所以当堆满的时候,判断当前元素和是否小于堆根元素,如果小于,就弹出这个最大元素,将当前元素进入最大堆。遍历完成之后,堆中的k个元素就是最小的k个元素。
*/
import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> ans = new ArrayList<>();
        if(input==null || k<=0 || k > input.length)
            return ans;
        //默认是最小堆,这里是最大堆 并且容量为k
        PriorityQueue<Integer> pq = new PriorityQueue<>(k,(o1,o2)->o2-o1);
        for(int n: input){
            if(pq.size()<k){
                pq.offer(n);
            }
            else if(pq.peek()>n){
                pq.poll();
                pq.offer(n);
            }
        }
        while(!pq.isEmpty()){
            ans.add(pq.poll());
        }
        return ans;
    }
}
/*
手写堆排序,然后返回排序后数组的前k个元素
*/
import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> ans = new ArrayList<>();
        if(input==null || k<=0 || k>input.length)
            return ans;
        heapSort(input);
        for(int i=0;i<k;i++)
            ans.add(input[i]);
        return ans;
    }
    private void heapSort(int[] arr){
        int len = arr.length;
        for(int i=len/2-1; i>=0; i--)//建立最大堆  从倒数第二层开始过滤 形成一个最大堆
            percDown(arr, i, len);
        for(int i=len-1;i>0;i--){//堆顶是最大的元素,将其与最后元素交换,然后将新的堆顶元素过滤 
            int t = arr[i];
            arr[i] = arr[0];
            arr[0] = t;
            percDown(arr, 0, i);
        }
    }
    private void percDown(int[] arr, int p, int n){//将指向的元素向下过滤
        int parent, child;
        int x = arr[p];
        for(parent=p; parent*2+1<n;parent=child){
            child = parent*2+1;
            if(child!=n-1 && arr[child]<arr[child+1])
                child++;
            if(x>=arr[child])
                break;
            else
                arr[parent] = arr[child];
        }
        arr[parent] = x; 
    }
}

3.2.Python代码

#手写堆排序
# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        ans = []
        if not tinput or k<=0 or k>len(tinput):
            return  ans
        self.heapSort(tinput)
        return tinput[:k]
    def heapSort(self, arr):
        def percDown(arr, p, n):
            x = arr[p]
            parent = p
            while parent*2+1<n:
                child = parent*2+1
                if child!=n-1 and arr[child]<arr[child+1]:
                    child += 1
                if x>=arr[child]:
                    break
                else:
                    arr[parent] = arr[child]
                parent = child
            arr[parent] = x
        l = len(arr)
        for i in range(l//2-1, -1, -1):
            percDown(arr, i, l)
        for i in range(l-1, 0, -1):
            arr[i], arr[0] = arr[0], arr[i]
            percDown(arr, 0, i)

猜你喜欢

转载自blog.csdn.net/qq_37888254/article/details/89786804
今日推荐