美文网首页
堆的应用:牛客网-求最小的K个数

堆的应用:牛客网-求最小的K个数

作者: huyongming | 来源:发表于2021-05-13 17:24 被阅读0次

题目

求最小的k个数
给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组

输入

[4,5,1,6,2,7,3,8],4
输出
[1,2,3,4]

分析

这是一个典型的堆应用问题,可以使用大顶堆来解决这个问题

  1. 拿输入数组的前K个数,来构建一个大顶堆
  2. 遍历数组,更新大顶堆
  3. 堆排序,输出有序数组

源码

import java.util.ArrayList;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
        if (k == 0 || input == null || k > input.length) {
            return new ArrayList<Integer>();
        } else {
            int[] heap = new int[k + 1];
            for (int i = 0; i < k; i++) {
                heap[i + 1] = input[i];
            }
            //初始化大顶堆
            heap(k, heap);
            //更新大顶堆
            for (int i = k; i < input.length; i++) {
                if (input[i] < heap[1]) {
                    heap[1] = input[i];
                    heapFromTop(1, k, heap);
                }
            }
            System.out.print("heap:");
            for (int i = 1; i <= k; i++) {
                System.out.print(heap[i] + ",");
            }
            System.out.println("");
            //堆排序
            ArrayList<Integer> list = new ArrayList<>();
            for (int num = k; num >= 1; num--) {
                list.add(0, heap[1]);
                heap[1] = heap[num];
                heapFromTop(1, num, heap);
            }
            return list;
        }
    }

    private static void heap(int k, int[] heap) {
        for (int i = k / 2; i >= 1; i--) {
            int left = i * 2;
            int right = i * 2 + 1;
            int tempIndex;
            if (right > k) {
                tempIndex = left;
            } else {
                tempIndex = heap[left] > heap[right] ? left : right;
            }
            if (heap[tempIndex] > heap[i]) {
                int temp = heap[tempIndex];
                heap[tempIndex] = heap[i];
                heap[i] = temp;
                heapFromTop(tempIndex, k, heap);
            }
        }
    }

    private static void heapFromTop(int top, int k, int[] heap) {
        for (int l = top; l <= k / 2; l++) {
            int left = l * 2;
            int right = l * 2 + 1;
            int tempIndex;
            if (right > k) {
                tempIndex = left;
            } else {
                tempIndex = heap[left] > heap[right] ? left : right;
            }
            if (heap[tempIndex] > heap[l]) {
                int temp = heap[tempIndex];
                heap[tempIndex] = heap[l];
                heap[l] = temp;
            } else {
                break;
            }
        }
    }
}

堆的知识

  1. 堆的定义:堆是一颗每个节点的左右孩子都小于(小顶堆)或者大于(大顶堆)根节点的完全二叉树;
  2. 堆的存储:由于是一颗完全二叉树,所以适合使用数组来存储,一般将堆顶元素存储在数组的下标为1的位置,这样第i个节点的左右孩子的位置就是:i*2,i*2+1;最后一颗叶子节点的位置是:size/2。
  3. 初始化堆:从最后一颗非叶子节点开始自底向上堆化,如果有节点交换,则对子节点进行自顶向下堆化
 private static void heap(int k, int[] heap) {
        for (int i = k / 2; i >= 1; i--) {
            int left = i * 2;
            int right = i * 2 + 1;
            int tempIndex;
            if (right > k) {
                tempIndex = left;
            } else {
                tempIndex = heap[left] > heap[right] ? left : right;
            }
            if (heap[tempIndex] > heap[i]) {
                int temp = heap[tempIndex];
                heap[tempIndex] = heap[i];
                heap[i] = temp;
                heapFromTop(tempIndex, k, heap);
            }
        }
    }

 private static void heapFromTop(int top, int k, int[] heap) {
        for (int l = top; l <= k / 2; l++) {
            int left = l * 2;
            int right = l * 2 + 1;
            int tempIndex;
            if (right > k) {
                tempIndex = left;
            } else {
                tempIndex = heap[left] > heap[right] ? left : right;
            }
            if (heap[tempIndex] > heap[l]) {
                int temp = heap[tempIndex];
                heap[tempIndex] = heap[l];
                heap[l] = temp;
            } else {
                break;
            }
        }
    }
  1. 更新堆:替换堆顶元素,然后自顶向下堆化
 heap[1] = input[i];
 heapFromTop(1, k, heap);
  1. 堆排序:堆顶元素有序,先获取堆顶元素,然后用最后一个节点的元素替换堆顶元素,堆大小-1,自顶向下堆化,再次获取堆顶元素,直到堆中只有一个元素
 ArrayList<Integer> list = new ArrayList<>();
  for (int num = k; num >= 1; num--) {
            list.add(0, heap[1]);
            heap[1] = heap[num];
            heapFromTop(1, num, heap);
   }

相关文章

  • 堆的应用:牛客网-求最小的K个数

    题目 求最小的k个数[https://www.nowcoder.com/practice/6a296eb82cf8...

  • 求最小的K个数

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

  • 优先队列找出最小的k个数

    优先队列内部维持了一个堆,堆的特点是堆顶元素最大(或最小),利用优先队列查找最小的k个数的方法:1、把前k个数当成...

  • 快排的partition算法解题

    最小的k个数,输入n个整数,找出其中最小的k个数可以建立大小为K的小顶堆。也可以运用partition函数进行求解...

  • 寻找最大的K个数

    解法1:可以使用容量为K的最小堆来存储最大的K个数,最小堆的堆顶元素就是最大K个数中最小的一个。每次新考虑一个数X...

  • JS 求最小的 K 个数

    题目描述:输入 n 个整数,找出其中最小的 k 个数。例如输入 4,5,1,6,2,7,3,8 这 8 个数字,则...

  • PriorityQueue 使用方法

    求最大k个元素的问题:使用小顶堆 求最小k个元素的问题:使用大顶堆 参考:1 采用PriorityQueue实现大...

  • 在一个无序数组中找到第k大的数

    这里是用了最小堆保存当前最大的k个数,堆顶即为top k中最小的数,每次和堆顶的数比较即可,实现直接用了stl的m...

  • 二叉堆(heap)

    堆数据结构对于获取最大值的K个数或者获取最小的K个数比较方便。 什么是堆 堆是一个完全二叉树,并且它可以使用一个数...

  • 最小方差划分

    给一个数组,求一个k值,使得前k个数的方差 + 后面n-k个数的方差最小 解题思路: 如果不考虑方差的概念,这题可...

网友评论

      本文标题:堆的应用:牛客网-求最小的K个数

      本文链接:https://www.haomeiwen.com/subject/khdxjltx.html