算法总结
1.数据流的第 K 大数值
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
题解:就是找一个第k大的元素,可以遍历,或者排序后查找。优解是用一个优先队列自动排序,这个队列维持一个前k大的元素,队头就是第k大元素。比如k=3,那这个队列就是维持一个第一,二,三大的元素。因为自动排序所以队列是第三大元素。是一个递增队列。
package com.chenghaixiang.jianzhi2.day20; import java.util.ArrayDeque; import java.util.PriorityQueue; import java.util.Queue; /** * @author 程海翔 * @school 石家庄铁道大学 */ public class Office059 { public static void main(String[] args) { int[] nums={4, 5, 8, 2}; KthLargest kthLargest=new KthLargest(1,nums); System.out.println(kthLargest.add(3)); } } //设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。 // //请实现 KthLargest 类: // // KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。 // int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。 class KthLargest { //PriorityQueue是优先队列,作用是保证每次取出的元素都是队列中权值最小的,这里涉及到了大小关系, //说白了是自动排序从小到大 //元素大小的评判可以通过元素自身的自然顺序(使用默认的比较器),也可以通过构造时传入的比较器。 PriorityQueue<Integer> queue; int k; public KthLargest(int k, int[] nums) { this.k=k; queue=new PriorityQueue<>(); for (int x:nums){ //调用add函数保证数据流中数据排序 add(x); } } public int add(int val) { queue.offer(val); if(queue.size()>k){ //检索并删除队头 //维持一个前k大的队列 //队头就是第k大的值 queue.poll(); } //检索不删除 return queue.peek(); } }
2.出现频率最高的 k 个数字
给定一个整数数组 nums
和一个整数 k
,请返回其中出现频率前 k
高的元素。可以按 任意顺序 返回答案。
题解:因为要统计出现频率所以用一个数组存储,用之前的题思路,我们添加这个数组进入一个集合能不能自动排序,但添加的是一个数组,所以要自定义比较器,自定义排序规则(难点)
package com.chenghaixiang.jianzhi2.day20; import java.util.*; /** * @author 程海翔 * @school 石家庄铁道大学 */ public class Office060 { public static void main(String[] args) { int[] a=new int[]{1,1,1,2,2,3}; Solution solution=new Solution(); solution.topKFrequent(a,2); } } //给定一个整数数组 nums 和一个整数 k ,请返回其中出现频率前 k 高的元素。可以按 任意顺序 返回答案。 class Solution { //堆 public int[] topKFrequent(int[] nums, int k) { Map<Integer,Integer> curr=new HashMap<>(); for (int num:nums){ //遍历数组统计各个数字出现的次数 curr.put(num,curr.getOrDefault(num,0)+1); } //初始化小顶堆 // int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数 //new Comparator<int[]>()自定义比较器,比较compare方法中自定义的比较,实现排序 //堆顶是次数出现最小的值 PriorityQueue<int[]> queue=new PriorityQueue<>(new Comparator<int[]>() { //返回负整数,零或正整数,第一个参数小于,等于或大于第二个参数。 @Override public int compare(int[] o1, int[] o2) { return o1[1]-o2[1]; } }); for (Map.Entry<Integer,Integer> entry:curr.entrySet()){ int num=entry.getKey(),count=entry.getValue(); if(queue.size()==k){ //保证堆中添加元素出现次数是比队头大 if(queue.peek()[1]<count){ queue.poll(); queue.offer(new int[]{num,count}); } }else { queue.offer(new int[]{num,count}); } } int[] res=new int[k]; for (int i=0;i<k;++i){ res[i]=queue.poll()[0]; } return res; } }