12 阅读2分钟

1 TopK问题

  • 堆求解TopK问题
  • 快排

1.1 最接近原点的 K 个点

class Solution {
    public int[][] kClosest(int[][] points, int k) {
        PriorityQueue<int[]> pq = new PriorityQueue<>((p1, p2) 
        ->  p2[0]*p2[0]+p2[1]*p2[1] - p1[0]*p1[0] - p1[1]*p1[1]);

        for(int[] point : points){
            // 如果堆中不足K个,直接将当前的point加入
            if(pq.size() < k){
                pq.offer(point);
            }else if(pq.comparator().compare(point, pq.peek())>0){
                // 否则,判断当前点的距离是否小于堆中的最大距离
                // 如果是,将堆中的最大距离poll出,将当前点加入堆中
                pq.poll();
                pq.offer(point);
            }
        }

        int[][] res = new int[pq.size()][2];
        int idx = 0;
        for(int[] point : pq){
            res[idx++] = point;
        }

        return res;
    }
}

1.2 前K个高频单词 - 力扣(LeetCode)

class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        int n = words.length;
        Map<String, Integer> map = new HashMap<>();
        for(String word : words){
            // 如果原本就有这个单词的话,计数器+1
            if(map.get(word) != null){
                int cnt = map.get(word);
                cnt++;
                map.put(word, cnt);
            }else{
                map.put(word, 1);   // 如果没有这个单词,则设置为1
            }
        }

        // 用小根堆
        PriorityQueue<Object[]> pq = new PriorityQueue<>((a, b) -> {
            // 如果词频不同,根据词频升序排序
            int c1 = (Integer)a[1];
            int c2 = (Integer)b[1];
            if(c1 != c2) return c1-c2;
            // 如果词频相同,根据字典序倒序
            String s1 = (String)a[0];
            String s2 = (String)b[0];
            return s2.compareTo(s1);
        });

        for(String word : map.keySet()){
            int cnt = map.get(word);
            // 堆中不足k个数,直接入堆
            if(pq.size() < k){
                pq.add(new Object[]{word, cnt});
            }else{
                Object[] peek = pq.peek();
                // 如果词频大于peek,入堆
                if(cnt > (Integer)peek[1]){
                    pq.poll();
                    pq.offer(new Object[]{word, cnt});
                }else if(cnt == (Integer)peek[1]){
                    // 词频相同,比较字典序
                    String top = (String)peek[0];
                    if(word.compareTo(top) < 0){
                        pq.poll();
                        pq.add(new Object[]{word, cnt});
                    }
                }
            }
        }

        List<String> ans = new ArrayList<>();
        while(!pq.isEmpty()) ans.add((String)pq.poll()[0]);
        Collections.reverse(ans);   // 记得反转

        return ans;
    }
}

2. 数据流中位数

2.1 数据流中的中位数

class MedianFinder {

    /** initialize your data structure here. */
    PriorityQueue<Integer> a,b;

    public MedianFinder() {
        a = new PriorityQueue<>();  // 小顶堆,存储较大的一半
        b = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆,存储较小的一半
    }
    
    public void addNum(int num) {
        if(a.size() != b.size()){
            a.add(num);
            b.add(a.poll());
        }else{
            b.add(num);
            a.add(b.poll());
        }
    }
    
    public double findMedian() {
        return a.size()!=b.size() ? a.peek() : (a.peek()+b.peek())/2.0;
    }
}

3. K路归并

3.1 合并 K 个升序链表 - 力扣(LeetCode)

class Solution {
    class Status implements Comparable<Status>{
        int val;
        ListNode ptr;

        Status(int val, ListNode ptr){
            this.val = val;
            this.ptr = ptr;
        }

        public int compareTo(Status s2){
            return this.val - s2.val;
        }
    }

    PriorityQueue<Status> queue = new PriorityQueue<Status>();

    public ListNode mergeKLists(ListNode[] lists) {
        // 加入优先队列中
        for(ListNode node : lists){
            if(node != null){
                queue.offer(new Status(node.val, node));
            }
        }

        ListNode head = new ListNode(0);
        ListNode tail = head;

        while(!queue.isEmpty()){
            Status f = queue.poll();
            tail.next = f.ptr;
            tail = tail.next;
            if(f.ptr.next != null){
                queue.offer(new Status(f.ptr.next.val, f.ptr.next));
            }
        }

        return head.next;
    }
}