Java用PriorityQueue实现topk排序

TopK思想:

https://blog.csdn.net/wufaliang003/article/details/82940218

题目描述

给定String类型的数组strArr,再给定整数k,请严格按照排名顺序打印 出次数前k名的字符串。

[要求]

如果strArr长度为N,时间复杂度请达到O(N \log K)O(NlogK)

 

输出K行,每行有一个字符串和一个整数(字符串表示)。
你需要按照出现出现次数由大到小输出,若出现次数相同时字符串字典序较小的优先输出
 

示例1

输入

复制

["1","2","3","4"],2

返回值

[["1","1"],["2","1"]]

示例2

输入

["1","1","2","3"],2

返回值

[["1","2"],["2","1"]]

import java.util.*;


public class Solution {
    /**
     * 题意要求是TopK问题,时间复杂度达到O(NlogK),并且相同大小要按字典排序,
     * 所以排序方法应该是堆排序或者快速选择排序。
     * 这里排序使用小顶堆,按值排序时是从小到大。当值相同时,比较str,这里重写堆节点的比较方法,
     * 值相同时,str字典序大的先入堆。
     * 最后,排序好的小顶堆输出k个数到结果集,结果集数组从尾部开始填充,
     * 这样小顶堆的数据刚好逆序,在结果集里的表现就是 按值排序是升序,值相同是字典小的在数组前面。
     * return topK string
     * @param strings string字符串一维数组 strings
     * @param k int整型 the k
     * @return string字符串二维数组
     */
    public String[][] topKstrings (String[] strings, int k) {
       
        if(strings==null || strings.length==0){
            return null;
        }
        
        HashMap<String,Integer> map = new HashMap();
        for(String s : strings){
            //初始化 数组中每个字符串默认出现一次
            map.put(s,map.getOrDefault(s,0)+1);
        }
        
        // 优先队列,实现小顶堆,输出到结果集就是堆的逆序,即倒序输出小顶堆,即大顶堆
        //https://blog.csdn.net/wufaliang003/article/details/82940218参考最小堆的思想
        PriorityQueue<Node> minHeap = new PriorityQueue();
        for(Map.Entry<String,Integer> entrySet : map.entrySet()){
            Node node = new Node(entrySet.getKey(),entrySet.getValue());
            //先用前k个元素生成一个小顶堆,这个小顶堆用于存储,当前最大的k个元素。
            if(minHeap.size() < k){
                minHeap.add(node);
            }else{
                // 堆中元素等于 k 个时
                // 当 node的值大于栈顶元素,或者值相同时node的字典小于栈顶元素 时(最小堆构建规则,就是如此)
                //这相当于上一个条件:先用前k个元素生成一个小顶堆,这个小顶堆用于存储,当前最大的k个元素。
                //接着,从第k+1个元素开始扫描,和堆顶(堆中最小的元素)比较,如果被扫描的元素大于堆顶,则替换堆顶的元素,并调整堆,
                //以保证堆内的k个元素,总是当前最大的k个元素。
                if(minHeap.peek().compareTo(node) < 0){
                    minHeap.poll();
                    minHeap.add(node);
                }
            }
        }
        
        String[][] result = new String[k][2];
        //正序弹出小顶堆上面的元素,数组逆序输出
        for(int i=k-1;i>=0;i--){
            Node node = minHeap.poll();
            result[i][0] = node.name;
            result[i][1] = String.valueOf(node.count); 
        }
        return result;
    }
    
    class Node implements Comparable<Node>{
        
        //对应上面Map里的key
        String name;
        //对应上面Map里的value
        int count;
        
        public Node(String name,int count){
            this.name = name;
            this.count = count;
        }
        
        @Override
        public int compareTo(Node node){
            //正常是通过Node对象里的count来比较大小的
            if(this.count > node.count){
                return 1;
            }else if(this.count < node.count){
                return -1;
            }else{
                //比如["2","2","1","1"]的情况 数组中字符串2出现2次 字符串1出现2次 这时候要求按字典顺序输出["1","2"]、["2","2"]1出现2次 2出现2次
                //此时使用原生的比较器 用2个Node对象的string进行字典顺序比较
                //上面的2个条件比较对象是堆顶的元素 被比较对象是要是否加入替代堆顶最小元素的元素 用的是count大小做比较
                //但此时Node值相同,应该比较的是要加入的node的name字典值,小于栈顶元素 才会重新进行构建最小堆 应该反过来比较
                return node.name.compareTo(this.name);
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值