180. 连续出现的数字

编写一个 SQL 查询,查找所有至少连续出现三次的数字。

+----+-----+
| Id | Num |
+----+-----+
| 1  |  1  |
| 2  |  1  |
| 3  |  1  |
| 4  |  2  |
| 5  |  1  |
| 6  |  2  |
| 7  |  2  |
+----+-----+
例如,给定上面的 Logs 表, 1 是唯一连续出现至少三次的数字。

+-----------------+
| ConsecutiveNums |
+-----------------+
| 1               |
+-----------------+

# Write your MySQL query statement below


select Distinct a.Num ConsecutiveNums from (
    select t.Num ,
    @cnt:=IF(@prev=t.Num,@cnt+1,1) cnt,
    @prev:=t.Num
    from Logs t,(select @prev:=null,@cnt:=0) r
) a where a.cnt>=3

语法解释:
1. IF(expr1,  expr2, expr3) //三元表达式
2. @pre:=10 // 变量赋值语法
3. 使用select 语句设置变量,可看做表,在datagrip中直接运行可以显示为表 
pre ==> 记录上一个值, cnt ==> 记录次数,
 select @pre:=null,  @cnt:=0 
4. 如果pre与t.num 相等,则cnt加1, 否则cnt重置为1
 @cnt:=IF(@pre=t.Num, @cnt+1, 1) cnt
5. 将生成的num与cnt次数的表,作为新的表 a
SELECT t.Num ,
       @cnt:=IF(@pre=t.Num, @cnt+1, 1) cnt,
       @pre:=t.Num pre
  FROM Logs t, (SELECT @pre:=null, @cnt:=0) b) a
<think>好的,我现在需要解决用户的两个问题:首先解释MySQL子查询排名逻辑的执行过程,然后提供使用MySQL解决力扣180题(连续出现的数字)的解决方案。让我先理清用户的需求和背景。 用户之前已经询问过关于SQL代码执行过程的问题,特别是涉及子查询的排名逻辑。现在他们希望更深入地理解MySQL中子查询排名的执行机制,可能是在准备面试或刷题时需要掌握这些概念。此外,用户提到了力扣180题,这题需要找出连续出现至少三次的数字,属于常见的SQL问题,通常考察窗口函数或自连接的使用。 首先,针对子查询排名的执行过程。用户之前提供的代码示例使用了子查询来计算排名,我需要详细解释其执行步骤,包括主查询和子查询的交互、逐行处理的方式以及性能特点。根据之前的引用内容,用户可能已经了解一些窗口函数的方法(如引用2中的dense_rank),但这里需要对比子查询方法和窗口函数的区别,尤其是执行过程和效率上的差异。 接下来是力扣180题的解决方案。这道题的关键在于识别连续出现的记录。常见的方法包括自连接或使用变量来跟踪连续出现的次数。但考虑到用户之前的问题中提到了子查询和窗口函数,可能需要提供多种解法,并比较它们的优缺点。例如,使用自连接三次的方法虽然直观,但可能在性能上有问题;而使用窗口函数(如lead/lag)会更高效,但需要MySQL 8.0+的支持。此外,用户可能还需要考虑如何处理重复数字但非连续的情况,比如数字中间有其他数字隔开的情况。 需要注意的是,用户提供的引用中有关于窗口函数的使用(引用2和3),以及连接操作的注意事项(引用5),这些都可以在解答中引用。例如,在解决连续数字问题时,如果使用自连接,需要正确选择JOIN类型,避免LEFT JOIN导致的结果错误(引用5)。同时,如果使用窗口函数,可以引用之前提到的排名函数(如rank() over)来处理。 在回答时,需要确保结构清晰,分步骤解释每个解决方案的执行过程,并比较不同方法的优劣。同时,用户可能希望看到具体的SQL代码示例,以及对其执行过程的详细解释,类似于之前提供的快速排序代码示例。此外,用户可能对性能优化感兴趣,所以需要讨论不同方法的时间复杂度和适用场景。 总结来说,我需要: 1. 详细解释子查询排名的执行过程,包括主查询逐行处理、子查询如何为每一行计算排名,以及相关的性能问题。 2. 提供力扣180题的多种解决方案,包括自连接、窗口函数和变量法,并分析各自的优缺点。 3. 引用用户之前的问题和提供的引用内容,确保回答的一致性和相关性。 4. 确保回答结构清晰,代码正确,并附上执行过程的解释,帮助用户逐步理解。 现在,我需要检查是否有遗漏的部分,例如子查询排名中的DISTINCT使用是否必要,或者在连续数字问题中如何处理多组连续的情况。同时,需要验证提供的SQL代码是否正确,并考虑不同MySQL版本的支持情况,如窗口函数在MySQL 8.0+才被支持,而变量法可能在旧版本中更适用。 最后,生成相关问题,帮助用户进一步巩固知识点,例如优化排名查询的方法,或者处理更复杂的连续出现条件的情况。</think>### **一、MySQL子查询排名逻辑执行过程详解** #### **1. 核心代码回顾** ```sql SELECT s1.score, (SELECT COUNT(DISTINCT s2.score) FROM Scores s2 WHERE s2.score >= s1.score) AS &#39;rank&#39; FROM Scores s1 ORDER BY s1.score DESC; ``` #### **2. 执行过程分步解析** 1. **主查询逐行扫描** - 从`Scores s1`表中逐行读每条记录的`score`值,每读一行,触发一次子查询。 - **示例数据流**:若数据为`[100, 100, 90, 80]`,主查询依次处理`100 → 100 → 90 → 80`。 2. **子查询动态计算排名** - 每次主查询读一行时,子查询执行以下逻辑: ```sql SELECT COUNT(DISTINCT s2.score) FROM Scores s2 WHERE s2.score >= s1.score -- 关联主查询的当前行 ``` - **关键步骤**: - 筛选所有`>=`当前分数的记录(如处理`100`时,筛选出`[100, 100, 90, 80]`中`>=100`的值)。 - 去重后统计唯一分数数量(如`100`去重后为`1`,`90`去重后统计`>=90`的分数为`100, 90`,结果为`2`)。 3. **结果组装与排序** - 主查询将每个`score`与子查询返回的`rank`组合,最终按`score DESC`排序输出。 #### **3. 性能与特性** - **时间复杂度**:$O(n^2)$,主查询$n$行 × 子查询全表扫描$n$次。 - **排名类型**:实现密集排名(DENSE_RANK),同分同排名且无间隔。 - **适用场景**:小数据集,兼容所有SQL版本(无需窗口函数)[^1]。 --- ### **二、力扣180题(连续出现的数字)解决方案** #### **题目描述** - 表`Logs`结构:`id INT, num INT` - 要求:找出所有**至少连续出现三次**的数字。 - 示例输入: ``` +----+-----+ | id | num | +----+-----+ | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 2 | | 5 | 1 | | 6 | 2 | | 7 | 2 | +----+-----+ ``` - 期望输出:`[1]`(仅数字1连续出现三次) --- #### **方案1:自连接法(兼容所有版本)** ##### **核心逻辑** 通过三次自连接,筛选连续三条记录中`num`相同的值。 ```sql SELECT DISTINCT a.num AS ConsecutiveNums FROM Logs a JOIN Logs b ON a.id = b.id - 1 AND a.num = b.num JOIN Logs c ON b.id = c.id - 1 AND b.num = c.num; ``` ##### **执行过程** 1. **连接条件**: - `a.id = b.id -1`确保`a`是`b`的前一条记录。 - `a.num = b.num`和`b.num = c.num`保证连续三条记录的`num`相同。 2. **去重**:使用`DISTINCT`避免重复结果。 3. **性能分析**: - **时间复杂度**:$O(n^3)$,三重连接导致性能低下。 - **适用场景**:数据量较小且需兼容老版本MySQL[^5]。 --- #### **方案2:窗口函数法(MySQL 8.0+)** ##### **核心逻辑** 使用`LAG`函数向前前两条记录的`num`,判断是否连续相同。 ```sql SELECT DISTINCT num AS ConsecutiveNums FROM ( SELECT num, LAG(num, 1) OVER (ORDER BY id) AS prev1, LAG(num, 2) OVER (ORDER BY id) AS prev2 FROM Logs ) AS tmp WHERE num = prev1 AND num = prev2; ``` ##### **执行过程** 1. **窗口函数计算**: - `LAG(num, 1)`获前一行的`num`。 - `LAG(num, 2)`获前两行的`num`。 2. **过滤条件**:若当前`num`与前两条记录的`num`均相同,则为目标结果。 3. **性能分析**: - **时间复杂度**:$O(n)$,单表扫描+窗口计算,效率显著高于自连接法[^2]。 --- #### **方案3:变量计数法(兼容老版本)** ##### **核心逻辑** 通过变量跟踪连续出现次数,动态统计连续三次的情况。 ```sql SELECT DISTINCT num AS ConsecutiveNums FROM ( SELECT num, @count := IF(@prev = num, @count + 1, 1) AS cnt, @prev := num FROM Logs, (SELECT @prev := NULL, @count := 0) AS init ORDER BY id ) AS tmp WHERE cnt >= 3; ``` ##### **执行过程** 1. **变量初始化**:`@prev`存储前一个`num`,`@count`统计连续次数。 2. **动态更新**: - 若当前`num`与前一个相同,`@count`自增1。 - 否则重置`@count`为1。 3. **过滤输出**:筛选`cnt >=3`的记录并去重。 4. **性能分析**: - **时间复杂度**:$O(n)$,单次扫描,效率最优。 --- ### **三、方案对比与选择** | 方法 | 优点 | 缺点 | 适用场景 | |---------------|--------------------------|--------------------------|-----------------------| | **自连接法** | 兼容所有SQL版本 | $O(n^3)$,性能差 | 极小数据集 | | **窗口函数法**| $O(n)$,代码简洁 | 需MySQL 8.0+ | 大数据集,现代环境 | | **变量法** | $O(n)$,兼容老版本 | 需处理变量初始化逻辑 | 老版本MySQL优化场景 | --- ### **四、扩展验证(处理非严格连续)** 若题目要求**至少三次出现(不要求连续)**,需改用分组统计: ```sql SELECT num FROM Logs GROUP BY num HAVING COUNT(*) >= 3; -- 仅统计出现次数,不限制连续性 ``` --- ### **五、相关问题** 1. 如何优化自连接法的性能? 2. 窗口函数`LAG`与`LEAD`的区别是什么? 3. 变量法中若`id`不连续,如何调整逻辑? 4. 如何查找连续出现N次的数字(N为任意值)?
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值