Skip to content

Commit ca10516

Browse files
committed
feat: add solutions to lc problem: No.1244
No.1244.Design A Leaderboard
1 parent 1c8ae4c commit ca10516

File tree

5 files changed

+269
-53
lines changed

5 files changed

+269
-53
lines changed

Diff for: solution/1200-1299/1244.Design A Leaderboard/README.md

+96-17
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,17 @@ leaderboard.top(3); // returns 141 = 51 + 51 + 39;
6363

6464
<!-- 这里可写通用的实现逻辑 -->
6565

66-
用哈希表存放每个 playerId 所对应的分数。
66+
**方法一:哈希表 + 有序列表**
6767

68-
计算 topK 时,取出所有的分数,进行排序,获取前 K 个分数,累加得到结果。
68+
我们用哈希表 $d$ 记录每个参赛者的分数,用有序列表 $rank$ 记录所有参赛者的分数。
69+
70+
当调用 `addScore` 函数时,我们先判断参赛者是否在哈希表 $d$ 中,如果不在,我们将其分数加入有序列表 $rank$ 中,否则我们先将其分数从有序列表 $rank$ 中删除,再将其分数加入有序列表 $rank$ 中,最后更新哈希表 $d$ 中的分数。时间复杂度 $O(\log n)$。
71+
72+
当调用 `top` 函数时,我们直接返回有序列表 $rank$ 中前 $K$ 个元素的和。时间复杂度 $O(K \times \log n)$。
73+
74+
当调用 `reset` 函数时,我们先移除哈希表 $d$ 中的参赛者,再将其分数从有序列表 $rank$ 中移除。时间复杂度 $O(\log n)$。
75+
76+
空间复杂度 $O(n)$。其中 $n$ 为参赛者的数量。
6977

7078
<!-- tabs:start -->
7179

@@ -74,19 +82,28 @@ leaderboard.top(3); // returns 141 = 51 + 51 + 39;
7482
<!-- 这里可写当前语言的特殊实现逻辑 -->
7583

7684
```python
85+
from sortedcontainers import SortedList
86+
87+
7788
class Leaderboard:
7889
def __init__(self):
79-
self.player_scores = {}
90+
self.d = defaultdict(int)
91+
self.rank = SortedList()
8092

8193
def addScore(self, playerId: int, score: int) -> None:
82-
self.player_scores[playerId] = self.player_scores.get(playerId, 0) + score
94+
if playerId not in self.d:
95+
self.d[playerId] = score
96+
self.rank.add(score)
97+
else:
98+
self.rank.remove(self.d[playerId])
99+
self.d[playerId] += score
100+
self.rank.add(self.d[playerId])
83101

84102
def top(self, K: int) -> int:
85-
scores = sorted(list(self.player_scores.values()), reverse=True)
86-
return sum(scores[:K])
103+
return sum(self.rank[-K:])
87104

88105
def reset(self, playerId: int) -> None:
89-
self.player_scores[playerId] = 0
106+
self.rank.remove(self.d.pop(playerId))
90107

91108

92109
# Your Leaderboard object will be instantiated and called as such:
@@ -102,28 +119,41 @@ class Leaderboard:
102119

103120
```java
104121
class Leaderboard {
105-
private Map<Integer, Integer> playerScores;
122+
private Map<Integer, Integer> d = new HashMap<>();
123+
private TreeMap<Integer, Integer> rank = new TreeMap<>((a, b) -> b - a);
106124

107125
public Leaderboard() {
108-
playerScores = new HashMap<>();
126+
109127
}
110128

111129
public void addScore(int playerId, int score) {
112-
playerScores.put(playerId, playerScores.getOrDefault(playerId, 0) + score);
130+
d.merge(playerId, score, Integer::sum);
131+
int newScore = d.get(playerId);
132+
if (newScore != score) {
133+
rank.merge(newScore - score, -1, Integer::sum);
134+
}
135+
rank.merge(newScore, 1, Integer::sum);
113136
}
114137

115138
public int top(int K) {
116-
List<Integer> scores = new ArrayList<>(playerScores.values());
117-
Collections.sort(scores, Collections.reverseOrder());
118-
int res = 0;
119-
for (int i = 0; i < K; ++i) {
120-
res += scores.get(i);
139+
int ans = 0;
140+
for (var e : rank.entrySet()) {
141+
int score = e.getKey(), cnt = e.getValue();
142+
cnt = Math.min(cnt, K);
143+
ans += score * cnt;
144+
K -= cnt;
145+
if (K == 0) {
146+
break;
147+
}
121148
}
122-
return res;
149+
return ans;
123150
}
124151

125152
public void reset(int playerId) {
126-
playerScores.put(playerId, 0);
153+
int score = d.remove(playerId);
154+
if (rank.merge(score, -1, Integer::sum) == 0) {
155+
rank.remove(score);
156+
}
127157
}
128158
}
129159

@@ -136,6 +166,55 @@ class Leaderboard {
136166
*/
137167
```
138168

169+
### **C++**
170+
171+
```cpp
172+
class Leaderboard {
173+
public:
174+
Leaderboard() {
175+
176+
}
177+
178+
void addScore(int playerId, int score) {
179+
d[playerId] += score;
180+
int newScore = d[playerId];
181+
if (newScore != score) {
182+
rank.erase(rank.find(newScore - score));
183+
}
184+
rank.insert(newScore);
185+
}
186+
187+
int top(int K) {
188+
int ans = 0;
189+
for (auto& x : rank) {
190+
ans += x;
191+
if (--K == 0) {
192+
break;
193+
}
194+
}
195+
return ans;
196+
}
197+
198+
void reset(int playerId) {
199+
int score = d[playerId];
200+
d.erase(playerId);
201+
rank.erase(rank.find(score));
202+
}
203+
204+
private:
205+
unordered_map<int, int> d;
206+
multiset<int, greater<int>> rank;
207+
};
208+
209+
/**
210+
* Your Leaderboard object will be instantiated and called as such:
211+
* Leaderboard* obj = new Leaderboard();
212+
* obj->addScore(playerId,score);
213+
* int param_2 = obj->top(K);
214+
* obj->reset(playerId);
215+
*/
216+
```
217+
139218
### **...**
140219
141220
```

Diff for: solution/1200-1299/1244.Design A Leaderboard/README_EN.md

+89-18
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,28 @@ leaderboard.top(3); // returns 141 = 51 + 51 + 39;
5555
### **Python3**
5656

5757
```python
58+
from sortedcontainers import SortedList
59+
60+
5861
class Leaderboard:
5962
def __init__(self):
60-
self.player_scores = {}
63+
self.d = defaultdict(int)
64+
self.rank = SortedList()
6165

6266
def addScore(self, playerId: int, score: int) -> None:
63-
self.player_scores[playerId] = self.player_scores.get(playerId, 0) + score
67+
if playerId not in self.d:
68+
self.d[playerId] = score
69+
self.rank.add(score)
70+
else:
71+
self.rank.remove(self.d[playerId])
72+
self.d[playerId] += score
73+
self.rank.add(self.d[playerId])
6474

6575
def top(self, K: int) -> int:
66-
scores = sorted(list(self.player_scores.values()), reverse=True)
67-
return sum(scores[:K])
76+
return sum(self.rank[-K:])
6877

6978
def reset(self, playerId: int) -> None:
70-
self.player_scores[playerId] = 0
79+
self.rank.remove(self.d.pop(playerId))
7180

7281

7382
# Your Leaderboard object will be instantiated and called as such:
@@ -81,28 +90,41 @@ class Leaderboard:
8190

8291
```java
8392
class Leaderboard {
84-
private Map<Integer, Integer> playerScores;
93+
private Map<Integer, Integer> d = new HashMap<>();
94+
private TreeMap<Integer, Integer> rank = new TreeMap<>((a, b) -> b - a);
8595

8696
public Leaderboard() {
87-
playerScores = new HashMap<>();
88-
}
8997

98+
}
99+
90100
public void addScore(int playerId, int score) {
91-
playerScores.put(playerId, playerScores.getOrDefault(playerId, 0) + score);
101+
d.merge(playerId, score, Integer::sum);
102+
int newScore = d.get(playerId);
103+
if (newScore != score) {
104+
rank.merge(newScore - score, -1, Integer::sum);
105+
}
106+
rank.merge(newScore, 1, Integer::sum);
92107
}
93-
108+
94109
public int top(int K) {
95-
List<Integer> scores = new ArrayList<>(playerScores.values());
96-
Collections.sort(scores, Collections.reverseOrder());
97-
int res = 0;
98-
for (int i = 0; i < K; ++i) {
99-
res += scores.get(i);
110+
int ans = 0;
111+
for (var e : rank.entrySet()) {
112+
int score = e.getKey(), cnt = e.getValue();
113+
cnt = Math.min(cnt, K);
114+
ans += score * cnt;
115+
K -= cnt;
116+
if (K == 0) {
117+
break;
118+
}
100119
}
101-
return res;
120+
return ans;
102121
}
103-
122+
104123
public void reset(int playerId) {
105-
playerScores.put(playerId, 0);
124+
int score = d.remove(playerId);
125+
if (rank.merge(score, -1, Integer::sum) == 0) {
126+
rank.remove(score);
127+
}
106128
}
107129
}
108130

@@ -115,6 +137,55 @@ class Leaderboard {
115137
*/
116138
```
117139

140+
### **C++**
141+
142+
```cpp
143+
class Leaderboard {
144+
public:
145+
Leaderboard() {
146+
147+
}
148+
149+
void addScore(int playerId, int score) {
150+
d[playerId] += score;
151+
int newScore = d[playerId];
152+
if (newScore != score) {
153+
rank.erase(rank.find(newScore - score));
154+
}
155+
rank.insert(newScore);
156+
}
157+
158+
int top(int K) {
159+
int ans = 0;
160+
for (auto& x : rank) {
161+
ans += x;
162+
if (--K == 0) {
163+
break;
164+
}
165+
}
166+
return ans;
167+
}
168+
169+
void reset(int playerId) {
170+
int score = d[playerId];
171+
d.erase(playerId);
172+
rank.erase(rank.find(score));
173+
}
174+
175+
private:
176+
unordered_map<int, int> d;
177+
multiset<int, greater<int>> rank;
178+
};
179+
180+
/**
181+
* Your Leaderboard object will be instantiated and called as such:
182+
* Leaderboard* obj = new Leaderboard();
183+
* obj->addScore(playerId,score);
184+
* int param_2 = obj->top(K);
185+
* obj->reset(playerId);
186+
*/
187+
```
188+
118189
### **...**
119190
120191
```
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
class Leaderboard {
2+
public:
3+
Leaderboard() {
4+
5+
}
6+
7+
void addScore(int playerId, int score) {
8+
d[playerId] += score;
9+
int newScore = d[playerId];
10+
if (newScore != score) {
11+
rank.erase(rank.find(newScore - score));
12+
}
13+
rank.insert(newScore);
14+
}
15+
16+
int top(int K) {
17+
int ans = 0;
18+
for (auto& x : rank) {
19+
ans += x;
20+
if (--K == 0) {
21+
break;
22+
}
23+
}
24+
return ans;
25+
}
26+
27+
void reset(int playerId) {
28+
int score = d[playerId];
29+
d.erase(playerId);
30+
rank.erase(rank.find(score));
31+
}
32+
33+
private:
34+
unordered_map<int, int> d;
35+
multiset<int, greater<int>> rank;
36+
};
37+
38+
/**
39+
* Your Leaderboard object will be instantiated and called as such:
40+
* Leaderboard* obj = new Leaderboard();
41+
* obj->addScore(playerId,score);
42+
* int param_2 = obj->top(K);
43+
* obj->reset(playerId);
44+
*/

0 commit comments

Comments
 (0)