Leetcode-Database-2021刷题记录
180. 连续出现的数字
题目链接:180. 连续出现的数字
1. 思路
- 题目给出的表中有连续的Id和无序Num,这种情况下连续出现的数字对应的Id也将是连续增加的,因此只需要判断对应的id是否连续递增即可
- 如果题目没给出id,可以用ROW_NUMBER()1开窗函数给Num标记连续递增的id
2. 实现方法
- 对原表Logs进行开窗,经过对Num的分区和排序后,现在生成了一个Num从小到大排序,且相同Num值为一个窗口标记连续递增的正数,我将这一列命名为orders
ROW_NUMBER()
Over(Partition by Num Order by Num)
as orders
- 例如题目中给出的案例经过这一步后会得到下表
- 该表就可以很快看出,id连续时,orders也会连续,因此问题又转化为寻找id和orders都连续超过3行以上的Num
id | Num | orders |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 1 | 3 |
5 | 1 | 4 |
4 | 2 | 1 |
- 由于这两列递增的步长一致,因此,orders - id as minus的值在orders和id都连续时,会得到一列相同的差值,那么就只需要计数差值count(1) group by minus,这个值大于3对应的Num就是题目要求找出的Num
3. 完整代码
# Write your MySQL query statement below
Select distinct
Num as ConsecutiveNums
From
( Select
Num
,(ranking - orders) as minus
,count(*) as cnt_same
from
( Select *
,ROW_NUMBER() Over(Partition by Num Order by Num) as orders
from(
Select *
,ROW_NUMBER() Over() as ranking
From Logs
) a
)b
group by Num, minus
)c
Where cnt_same >= 3
;
4.同类拓展
- 该题只要求连续3次以上的数,实际上一开始很快可以想到用LEAD()或者LAG()2函数直接解决这个问题,只需要移动两次Num列,使得每个id都能对应原本的Num以及下一行的Num、下两行的Num,这三个数都相等,那么就满足了>=3的条件,取出所有这样的Num即可
- 但如果要求连续N次以上的数,那么上述原本就效率不高的解决方法就变得无法实现了,而3中给出的代码只需要将cnt_same字段设置为大于等于N就可以解除任意N值的同类题
- 连续重复问题也可变体为连续大于,连续小于,或者连续满足任何条件,下面的第185题,也正是连续出现问题的一个变体形式