介绍:对的定义和应用。
1 构造一个堆
(1)每次新增操作之后,需要调整堆siftUpComparable:将最后一个元素endIndex和(endIndex-1)/2的元素比较,如果比这个父元素大,就上移动。
(2)每次获取array[0]元素之后,需要调整堆siftDownComparable:将最后一个元素放置在a[0]执行下移动,和(currentIndex*2+1),(currentIndex*2+2)两个元素,如果比这两个子元素都大,那么此时就不执行下移动。否则选择这两个子元素最大的那个与这个元素替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
/** * 在java中通过PriorityQueue表示heap。 * 1、存储画图时,一次画出树的节点就可以: * 2、siftup:用到了递归,position和fater交换,直到postion为0 * 3、siftdown: 用到了递归,position和两个son中最大值比较,直到都比son都大或者son超出边界。 */ public class Heap { public List<Integer> buildHead(List<Integer> input) { List<Integer> heapList = Lists.newArrayList(); for (Integer value : input) { add(heapList, value); } return heapList; } public void add(List<Integer> heap, Integer value) { // 添加元素到末尾 heap.add(heap.size(), value); // 执行siftUp siftUp(heap, heap.size() - 1, value); } public Integer poll(List<Integer> heap) { int result = heap.get(0); heap.set(0, heap.get(heap.size() - 1)); heap.remove(heap.size() - 1); siftDown(heap, 0, heap.get(0)); return result; } /** * 1、中止条件 * 2、数据交换 * @param heap * @param position * @param value */ private void siftUp(List<Integer> heap, int position, int value) { // 中止条件 if (position == 0) { return; } int father = (position - 1) / 2; if (heap.get(father) >= value) { return; } else { // 数据交换 heap.set(position, heap.get(father)); heap.set(father, value); } siftUp(heap, father, value); } /** * 1、中止条件 * 2、数据交换 * @param heap * @param postion * @param value */ private void siftDown(List<Integer> heap, int postion, int value) { int son = 2 * postion + 1; // 1.中止条件 if (son > heap.size()-1) { return; } // 2.数据交换 if (value >= heap.get(son)) { son = son + 1; if (son <= heap.size() && heap.get(son) > value) { heap.set(postion, heap.get(son)); heap.set(son, value); }else { return; } } else { int max = heap.get(son); // 如果两个子节点都大于当前节点,选取最大职责 if (son+1<= heap.size() && heap.get(son+1) > value) { if(max < heap.get(son+1)){ max = heap.get(son+1); son = son+1; } } heap.set(postion, max); heap.set(son, value); } siftDown(heap, son, value); } public static void main(String[] args) { Heap heap = new Heap(); List<Integer> input = Lists.newArrayList(10, 3, 8, 15, 18, 19); List<Integer> result = heap.buildHead(input); System.out.println("reuslt=" + result); System.out.println("poll 0="+heap.poll(result)); System.out.printf("reuslt=" + result); } } |
2 查询top N
实例1 数组最小K个数
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。https://leetcode-cn.com/problems/smallest-k-lcci/
1 2 |
输入: arr = [1,3,5,7,2,4,6,8], k = 4 输出: [1,2,3,4] |
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Solution { public int[] smallestK(int[] arr, int k) { PriorityQueue<Integer> priority = new PriorityQueue<Integer>(); for(Integer num : arr){ priority.add(num); } int result[] = new int[k]; for(int i=0;i<k;i++){ result[i] = priority.poll(); } return result; } } |
实例2 前k高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素 。https://leetcode-cn.com/problems/top-k-frequent-elements/
1 2 3 |
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] |
思路: 借助Map和优先级队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class Solution { public int[] topKFrequent(int[] nums, int k) { // 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值 HashMap<Integer,Integer> map = new HashMap(); for(int num : nums){ if (map.containsKey(num)) { map.put(num,map.get(num) + 1); } else { map.put(num, 1); } } // 遍历map,构建堆 PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return map.get(b) - map.get(a); } }); for (Integer key : map.keySet()) { pq.add(key); } int[] result = new int[k]; for(int i=0; i<k ;i++){ result[i] = pq.poll(); } return result; } } |