LeetCode:Rank Scores

岁酱吖の 提交于 2020-04-14 00:52:28

【今日推荐】:为什么一到面试就懵逼!>>>

1、题目名称

Rank Scores(按分数排名次)

2、题目地址

https://leetcode.com/problems/rank-scores/

3、题目内容

按分数排名次,如果两个Id的分数一样,那么他们的名次是一样的,排名从1开始。注意,每组分数的名次,都是上一组分数名次加一。

例如,表Scores中有这样一组数据:

+----+-------+
| Id | Score |
+----+-------+
| 1  | 3.50  |
| 2  | 3.65  |
| 3  | 4.00  |
| 4  | 3.85  |
| 5  | 4.00  |
| 6  | 3.65  |
+----+-------+

排名后输出的数据应该为:

+-------+------+
| Score | Rank |
+-------+------+
| 4.00  | 1    |
| 4.00  | 1    |
| 3.85  | 2    |
| 3.65  | 3    |
| 3.65  | 3    |
| 3.50  | 4    |
+-------+------+

4、初始化数据库脚本

在MySQL数据库中建立一个名为LEETCODE的数据库,用MySQL命令行中的source命令执行下面脚本:

-- 执行脚本前必须建立名为LEETCODE的DATABASE
USE LEETCODE;
 
DROP TABLE IF EXISTS Scores;
CREATE TABLE Scores (
  Id INT NOT NULL PRIMARY KEY,
  Score FLOAT
);
 
INSERT INTO Scores (Id, Score) VALUES (1, 3.50);
INSERT INTO Scores (Id, Score) VALUES (2, 3.65);
INSERT INTO Scores (Id, Score) VALUES (3, 4.00);
INSERT INTO Scores (Id, Score) VALUES (4, 3.85);
INSERT INTO Scores (Id, Score) VALUES (5, 4.00);
INSERT INTO Scores (Id, Score) VALUES (6, 3.65);

5、先参考以下另外两种排名方法

排名的方式有很多种,抛开这道题目来说,常见的排名方式有两种:

第一种排名方式,是直接按分数对成员进行排列,名次从1开始依次递增,当两个人分数相同时,也要按出现的先后顺序或其他规律分出先后。这样排序的SQL语句如下:

SELECT Score, @Counter := @Counter + 1 AS Rank
FROM Scores, (SELECT @Counter := 0) AS C
ORDER BY Score DESC;

排序后的截图如下:

(这个SQL同时也适用于给某一组查询结果添加行号)

第二种排名方式,是按分数对成员排列,如果两个Id分数相同,则名次相同,但不影响排名靠后人的名次。例如某比赛两个人并列第一,那么这个比赛就不再有第二名,得分第二高的人会被算作第三名。这样排序的SQL语句如下:

SELECT S1.Score, (
  SELECT COUNT(Score) + 1
  FROM Scores S2
  WHERE S1.Score < S2.Score) AS Rank
FROM Scores S1
ORDER BY S1.Score DESC;

排序后的截图如下:

6、解题SQL

我想出的方法是用DISTINCT关键字,先排出分数(Score)的名次保存在一个临时结果集中,在跨原表和这个临时结果集匹配出各个Id对应的名次。一个实现此思路的SQL语句为:

SELECT A.Score, B.Rank
FROM Scores AS A, (
  SELECT Score, @Counter := @Counter + 1 AS Rank
  FROM (SELECT DISTINCT Score FROM Scores) AS DIS_S, (SELECT @Counter := 0) AS C
  ORDER BY Score DESC) AS B
WHERE A.Score = B.Score
ORDER BY A.Score DESC;

查询结果截图如下:

7、其他解题SQL

后来我又查看了以下原题目的Dicuss板块,里面有很多不同的SQL语句实现这个功能,尤其是这个帖子:

https://leetcode.com/discuss/40116/simple-short-fast

现将几个SQL和相关思路整理后列在下面

1)使用两个变量rank和prev存储当前的名次和前一个名次的分数,分数变化时,名次加一

SELECT
  Score,
  @rank := @rank + (@prev <> (@prev := Score)) Rank
FROM
  Scores,
  (SELECT @rank := 0, @prev := -1) Init
ORDER BY Score DESC;

2)每个Id的Rank值,是得分小于该Id的数据行数

SELECT Score, (
  SELECT COUNT(DISTINCT Score) 
  FROM Scores 
  WHERE Score >= s.Score) Rank
FROM Scores s
ORDER BY Score DESC;

3)和前一个方法类似

SELECT Score, (
  SELECT COUNT(*) 
  FROM (
    SELECT DISTINCT Score S 
    FROM Scores) AS Tmp
  WHERE S >= Score) AS Rank
FROM Scores
ORDER BY Score DESC;

4)下面这个方法,也是选出比当前Id得分高的得分的个数,作为当前Id对应的名次

SELECT S.Score, COUNT(DISTINCT T.Score) AS Rank
FROM Scores S 
JOIN Scores T ON S.Score <= T.Score
GROUP BY S.Id
ORDER BY S.Score DESC

END

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!