加粗样式# 347. 前 K 个高频元素
快排
排序之后取前k个就可以了
小顶堆
使用小顶堆
-
当小顶堆的size == k 比较下一个数比小顶堆的最小值
- 更小或等于:抛弃
- 更大:替换
-
当小顶堆的size < k 的时候,无脑添加就可以了
代码如下:
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num,map.getOrDefault(num,0)+1);
}
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o1.getValue()-o2.getValue();
}
});
// PriorityQueue<int[]> priorityQueue = new PriorityQueue<>(new Comparator<int[]>() {
// @Override
// public int compare(int[] o1, int[] o2) {
// return o1[1]-o2[1];
// }
// });
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (queue.size()==k){
if (queue.peek().getValue()<entry.getValue()){
queue.poll();
queue.offer(entry);
}
}else {
queue.offer(entry);
}
}
int[] res = new int[k];
for (int i = 0; i < k; i++) {
res[i] = queue.poll().getKey();
}
return res;
}
215. 数组中的第K个最大元素
基于快排的分治
基于堆排序的选择方法
大顶堆
建立二叉树,调成成大顶堆,最后做 k-1 次删除即可
public static int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int num : nums) {
priorityQueue.offer(num);
}
for (int i = 1; i < k; i++) {
priorityQueue.poll();
}
return priorityQueue.poll();
}
小顶堆:
只存k个,堆顶元素比当前元素小就交换,一直保证队列里存的是最大的k个,
最后取堆顶就是最大的元素
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
for (int num : nums) {
if (priorityQueue.size()==k){
if (priorityQueue.peek() < num){
priorityQueue.poll();
priorityQueue.offer(num);
}
}else {
priorityQueue.offer(num);
}
}
return priorityQueue.poll();
}
堆
java里的优先队列:PriorityQueue 默认是小根堆
自己实现一个:
重点:
heapify() 将一个数组构建成大顶堆
down()将一个元素下潜
up() 将一个元素上浮
import java.util.Arrays;
/**
* @description: TODO
* @author: Liang Zi cao
* @DATE: 2023/7/28
* Talk is cheap. Show me the code
**/
public class MyHeap {
public static void main(String[] args) {
MyHeap myHeap = new MyHeap(new int[]{1, 2, 3, 4, 5 , 6, 7});
System.out.println(Arrays.toString(myHeap.array));
myHeap.offer(8);
System.out.println(Arrays.toString(myHeap.array));
myHeap.heapSort();
System.out.println(Arrays.toString(myHeap.array));
}
int[] array;
int size;
public MyHeap(int capaticy) {
this.array = new int[capaticy];
this.size = capaticy;
}
public MyHeap(int[] array) {
this.array = array;
this.size = array.length;
heapify();
}
public void heapify(){
//找到最后一个叶子结点
int lastIndex = size / 2 -1 ;
// 将起下潜
for (int i = lastIndex ;i>=0;i--){
down(i);
}
}
/**
* 将parent 索引处的元素下潜,于两个孩子较大的比较并交换,只到没孩子或者孩子没它大
* @param parent 要交换的值的索引
*
*/
private void down(int parent) {
int left = getLeft(parent);
int right = getRight(parent);
//找三个节点中间最大的索引
int max = parent;
if(left< size && array[left] > array[max]){
max = left;
}
if(right< size && array[right] > array[max]){
max = right;
}
//找到了一个更大的孩子
if (max != parent){
//交换
swap(parent,max);
// 递归执行 也就是让这个节点继续下潜
down(max);
}
}
/**
* 上浮,从尾部上浮 知道小于父元素,或者堆顶
* @param
*/
private void up( int index) {
int parent = ( index - 1 ) / 2;
if (parent>=0 && array[index] > array[parent]){
swap(index,parent);
up(parent);
}
}
public void heapSort(){
while (size > 1 ){
swap(0,size-1);
size--;
down(0);
}
}
/**
* 往堆的尾部添加元素
* @param val
* @return
*/
public boolean offer(int val){
size++;
array = Arrays.copyOf(array,size);
array[size-1] = val;
up(size-1);
return true;
}
public int peek(){
if (size==0){
throw new RuntimeException("null");
}
return array[0];
}
public int poll(){
if (size==0){
throw new RuntimeException("null");
}
int temp = array[size-1];
swap(0,size-1);
size--;
array = Arrays.copyOf(array,size);
down(0);
return temp;
}
public int deleteByIndex(int index){
if (index>size-1){
throw new RuntimeException("null");
}
int temp = array[index];
swap(index,size-1);
size--;
array = Arrays.copyOf(array,size);
down(index);
return temp;
}
/**
* 交换
* @param parent
* @param max
*/
private void swap(int parent, int max) {
int tmp = array[parent];
array[parent] = array[max];
array[max] = tmp;
}
/**
* 获得右孩子的索引值
* @param parent
* @return
*/
private int getRight(int parent) {
return parent*2 + 2;
}
/**
* 获得左孩子的索引值
* @param parent
* @return
*/
private int getLeft(int parent) {
return parent*2+1;
}
}