TopN问题堆排序求解

出现次数的TopK问题

http://www.nowcoder.com/questionTerminal/fd711bdfa0e840b381d7e1b82183b3ee

  1. 统计各个字符出现次数,使用Map
  2. 创建初始堆(大顶堆),定义出现次数大的字符串较大,出现次数相同是自然序较前的串较大
  3. 依次去K个堆顶元素并调整堆
import java.util.*;


public class Solution {
    /**
     * return topK string
     * @param strings string字符串一维数组 strings
     * @param k int整型 the k
     * @return string字符串二维数组
     */
    public String[][] topKstrings (String[] strings, int k) {
        if(null == strings || strings.length == 0) {
            return new String[0][];
        }

        String[][] result = new String[k][];
        // 统计各个字符串出现次数
        Map<String,Integer> cntMap = new HashMap();
        for(String s : strings) {
            cntMap.put(s, cntMap.getOrDefault(s, 0)+1);
        }

        // 创建初始堆 大顶堆
        Node[] heapArr = new Node[cntMap.size()+1];
        int idx = 0;
        for(Map.Entry<String,Integer> entry : cntMap.entrySet()) {
            Node node = this.new Node(entry.getKey(), entry.getValue());
            heapArr[++idx] = node;
        }
        // 调整初始堆
        for(int i = idx/2; i > 0; --i) {
            shift(heapArr, i, heapArr.length);
        }

        // 取前K个
        int limit = heapArr.length-1;
        for(int i = 1; i <= k && i <= limit; ++i) {
            String[] r = new String[]{heapArr[1].val, String.valueOf(heapArr[1].cnt)};
            result[i-1] = r;

            Node temp = heapArr[1];
            heapArr[1] = heapArr[limit];
            heapArr[limit] = temp;
            --limit;

            // 调整堆
            shift(heapArr, 1, limit+1);
        }
        return result;
    }

    // 堆调整方法
    private void shift(Node[] heapArr, int startIdx, int endIdx) {
        int childIdx = 2 * startIdx;
        if(childIdx+1 < endIdx && heapArr[childIdx+1].compareTo(heapArr[childIdx]) > 0) {
            childIdx = childIdx + 1;
        }

        if(childIdx < endIdx && heapArr[childIdx].compareTo(heapArr[startIdx]) > 0) {
            Node temp = heapArr[childIdx];
            heapArr[childIdx] = heapArr[startIdx];
            heapArr[startIdx] = temp;
            shift(heapArr, childIdx, endIdx);
        }
    }

    // 堆结点定义
    class Node implements Comparable<Node> {
        String val;
        int cnt;
        Node() {}
        Node(String val, int cnt) {
            this.val = val;
            this.cnt = cnt;
        }

        //定义比较方法: cnt 大的大, cnt相同时,val自然序小的大
        public int compareTo(Node node) {
            if(this.cnt != node.cnt) {
                return this.cnt - node.cnt;
            } else {
                return -this.val.compareTo(node.val);
            }
        }
    }
}
全部评论
这个能做到NlogK的复杂度吗?总感觉不太像啊,有大佬可以给分析下吗?
1 回复 分享
发布于 2021-06-24 15:45
明显用小顶堆更方便。
点赞 回复 分享
发布于 2021-07-08 10:40
37行 i<=limit 这个条件判断没必要,感谢!!!
点赞 回复 分享
发布于 2021-10-06 16:13
可以用PriorityQueue代替堆,就没必要自己写一个了
点赞 回复 分享
发布于 2021-11-30 13:32

相关推荐

点赞 评论 收藏
分享
9 1 评论
分享
牛客网
牛客企业服务