TopK问题

实现思路:

  1. 选择小顶堆:维护当前最高的K个元素,堆顶是这K个中的最小值。新元素若大于堆顶,则替换堆顶并调整堆,确保堆中始终为Top K大元素。

  2. 插入逻辑:堆未满时直接插入;堆满时,新元素大于堆顶则替换,否则忽略。

  3. 获取排行榜:取出堆元素并按热度降序排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.*;

public class HotSearchRanking {

static class HotSearchItem {
private final String keyword;
private final int heat;

public HotSearchItem(String keyword, int heat) {
this.keyword = keyword;
this.heat = heat;
}

public int getHeat() {
return heat;
}

public String getKeyword() {
return keyword;
}

@Override
public String toString() {
return keyword + "(" + heat + ")";
}
}

private final PriorityQueue<HotSearchItem> minHeap;
private final int k;

public HotSearchRanking(int k) {
this.k = k;
// 初始化小顶堆,按热度升序排序
this.minHeap = new PriorityQueue<>(Comparator.comparingInt(HotSearchItem::getHeat));
}

public void add(HotSearchItem item) {
if (item == null) return;
if (minHeap.size() < k) {
minHeap.offer(item);
} else {
// 仅当新元素热度大于堆顶时替换
if (item.getHeat() > minHeap.peek().getHeat()) {
minHeap.poll();
minHeap.offer(item);
}
}
}

public List<HotSearchItem> getTopK() {
List<HotSearchItem> result = new ArrayList<>(minHeap);
// 按热度降序排序以形成排行榜
result.sort(Comparator.comparingInt(HotSearchItem::getHeat).reversed());
return result;
}

public static void main(String[] args) {
HotSearchRanking ranking = new HotSearchRanking(3);
ranking.add(new HotSearchItem("Java", 50));
ranking.add(new HotSearchItem("Python", 30));
ranking.add(new HotSearchItem("C++", 70));
ranking.add(new HotSearchItem("JavaScript", 60));
ranking.add(new HotSearchItem("Go", 65));

List<HotSearchItem> top = ranking.getTopK();
System.out.println("实时热搜排行榜TOP3:");
for (HotSearchItem item : top) {
System.out.println(item);
}
}
}

该方法确保每次插入和调整的时间复杂度为O(log K),获取排行榜的时间复杂度为O(K log K),适合处理实时更新的热搜数据。


TopK问题
http://bloomivy.github.io/2025/01/29/TopK问题/
作者
Bloom
发布于
2025年1月29日
许可协议