代码改变世界

LeetCode:Rank Scores

2015-04-09 20:50  大脑溢出  阅读(1056)  评论(0编辑  收藏  举报

做到这题时卡了不少时间,参考了别人的解法,觉得挺不错的,还挺巧妙。

SELECT s2.Score,s1.Rank From
(
SELECT S1.Score, COUNT(*) as Rank
    FROM 
        (SELECT DISTINCT Score from Scores) as S1,
        (SELECT DISTINCT Score from Scores) as S2 
        Where S1.Score<=S2.Score
        Group By S1.Score
) s1 ,Scores s2 
WHERE s1.Score = s2.Score Order BY s2.Score desc

 

简单回顾一下题目,

+----+-------+
| 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    |
+-------+------+
这种效果,一般情况下用存储过程会比较方便地得到,但既然一句SQL可以解决,便学习一下罢。贴出的解法中的子查询起了关键作用
SELECT S1.Score, COUNT(*) as Rank
    FROM 
        (SELECT DISTINCT Score from Scores) as S1,
        (SELECT DISTINCT Score from Scores) as S2 
        Where S1.Score<=S2.Score
        Group By S1.Score
)

(该子查询的外层查询仅仅是一个连接操作然后排序,比较简明,故不赘述)

这个子查询如果单独执行,可以得到下面的结果:

T~SB86]K8(XLAMF`3EB~(EA

可以很清楚地看到,得到了一种“排序”效果,那么为什么会得到这种效果呢,我们可以进一步拆解:

SELECT S1.Score , Count(*) S2.Score as Rank
    FROM 
        (SELECT DISTINCT Score from Scores) as S1,
        (SELECT DISTINCT Score from Scores) as S2 
        Where S1.Score<=S2.Score

这个子查询我们对其稍作修改,以便更直观地观察其结果,如果单独执行,得到如下结果:

 

3(3QUSY2A[)TW]2`_SVD[TA

我们可以看到,S1.Score与S2.Score进行<=操作之后,得到了这样的结果,我们知道,俩字段的比较操作,会将左边表的字段依次与右边表的字段值逐个比较,这里我们可以看到,对于左表的3.5来说,右边表有四个值满足<=的比较条件,于是,左边表的3.5会出现4次,而右边的值则是满足比较条件的值。

于是,当所有的字段比较完成之后,我们可以总结出,因为每一个字段在右边去比较的时候,总会将比其小的值筛一个出去(因为是Distinct操作,不会存在重复值),这么一来,左边表的字段的值每迭代到一个更大的值,其在结果集中出现的次数一定比上一个次小值少一次,最后将其做Group By操作,这么一来,就得到了“排序”效果。