Skip to content

Commit 76e82f6

Browse files
committed
leetcode 178. Rank Scores
1 parent 627265c commit 76e82f6

3 files changed

Lines changed: 539 additions & 0 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# 解説
2+
3+
## ✅ 解法 1(推奨 / MySQL 8.0+)
4+
5+
```sql
6+
SELECT
7+
score,
8+
DENSE_RANK() OVER (ORDER BY score DESC) AS `rank`
9+
FROM Scores
10+
ORDER BY score DESC;
11+
```
12+
13+
### ポイント 1
14+
15+
- `DENSE_RANK()` は「同点は同順位」「次の順位は連番(穴なし)」を自動で満たします。
16+
- 問題要件の並び順は `ORDER BY score DESC` だけで OK(ID 順は不要)。
17+
18+
---
19+
20+
## ✅ 解法 2(互換 / MySQL 5.7 など)
21+
22+
ウィンドウ関数が使えない環境では、**相関サブクエリ**で「自分より高い**異なる**スコアの個数 + 1」を順位にします。
23+
24+
```sql
25+
SELECT
26+
s1.score,
27+
1 + (
28+
SELECT COUNT(DISTINCT s2.score)
29+
FROM Scores AS s2
30+
WHERE s2.score > s1.score
31+
) AS `rank`
32+
FROM Scores AS s1
33+
ORDER BY s1.score DESC;
34+
```
35+
36+
### ポイント 2
37+
38+
- `COUNT(DISTINCT s2.score)` により**同点は同じ順位**になる(穴なし= DENSE の性質)。
39+
- シンプルで確実ですが、データ量が多いと相関サブクエリで重くなることがあります。
40+
41+
---
42+
43+
## (参考)CTE で「重複除去 → 順位 → 突き合わせ」の段階を明示(MySQL 8.0+)
44+
45+
概念的な段階(Distinct → Rank → Join)をクエリ上でも表したい場合:
46+
47+
```sql
48+
WITH ds AS (
49+
SELECT DISTINCT score FROM Scores
50+
),
51+
rr AS (
52+
SELECT
53+
score,
54+
DENSE_RANK() OVER (ORDER BY score DESC) AS `rank`
55+
FROM ds
56+
)
57+
SELECT s.score, rr.`rank`
58+
FROM Scores AS s
59+
JOIN rr USING (score)
60+
ORDER BY s.score DESC;
61+
```
62+
63+
---
64+
65+
## 図解:処理の流れ(ウィンドウ関数版)
66+
67+
> 余計な HTML タグや複雑な改行を排し、Mermaid が壊れにくい最小構成にしています。
68+
69+
```mermaid
70+
flowchart TB
71+
A[Scores 全行] --> B[降順ソート: score DESC]
72+
B --> C[DENSE_RANK を各行に適用]
73+
C --> D[結果を score DESC で出力]
74+
```
75+
76+
---
77+
78+
## 図解:DENSE_RANK の考え方(概念)
79+
80+
```mermaid
81+
flowchart TB
82+
A[スコア集合] --> B[等しいスコアをグループ化]
83+
B --> C[高いスコアから順位を付与]
84+
C --> D[同点は同じ順位]
85+
D --> E[次の異なるスコアは直後の整数順位]
86+
```
87+
88+
---
89+
90+
## サンプルに対する出力イメージ
91+
92+
入力:
93+
94+
```text
95+
id | score
96+
---+-------
97+
1 | 3.50
98+
2 | 3.65
99+
3 | 4.00
100+
4 | 3.85
101+
5 | 4.00
102+
6 | 3.65
103+
```
104+
105+
出力(どの解法でも同じ):
106+
107+
```text
108+
score | rank
109+
------+------
110+
4.00 | 1
111+
4.00 | 1
112+
3.85 | 2
113+
3.65 | 3
114+
3.65 | 3
115+
3.50 | 4
116+
```
117+
118+
---
119+
120+
## つまずきポイントと対策
121+
122+
- **表示の小数桁**`score``DECIMAL(?,2)` であれば「4.00」のように 2 桁が保たれます。
123+
もし `FLOAT/DOUBLE` なら `ROUND(score, 2)` で揃えると安全です(問題文は DECIMAL 前提)
124+
- **順位の穴**`RANK()` は「穴あり」になるので、本問題は**必ず `DENSE_RANK()`** を使うか、相関サブクエリで「高い異なるスコア数 + 1」を計算してください。
125+
- **パフォーマンス**:巨大テーブルではウィンドウ関数が高速なことが多いです。5.7 の相関サブクエリ版はインデックス(`score`)である程度は緩和できます。
126+
127+
---

0 commit comments

Comments
 (0)