当前位置: 首页 > article >正文

【LeetCode 题解】数据库:180. 连续出现的数字

一、问题描述

给定一个Logs表,包含自增 ID 和数字字段:

CREATE TABLE Logs (
    id INT PRIMARY KEY AUTO_INCREMENT,
    num VARCHAR(50)
);

要求编写 SQL 查询,找出所有至少连续出现三次的数字。例如:

+----+-----+
| id | num |
+----+-----+
| 1  | 1   |
| 2  | 1   |
| 3  | 1   |
| 4  | 2   |
+----+-----+

输出应为:

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

二、核心思路解析

问题本质

需要识别表中连续出现至少三次的相同数字。关键点在于:

  1. 连续条件:相邻行的num值相同

  2. 次数统计:连续次数≥3 次

  3. 去重需求:相同数字只需返回一次

关键技术点

1. 如何判断连续?
  • 自连接法:通过表自连接比较相邻行

  • 窗口函数法:使用LAG()获取前一行数据

2. 如何统计连续次数?
  • 滑动窗口:检查当前行与前两行是否相同

  • 状态标记:用变量记录当前连续状态

三、解决方案详解

方法一:自连接法

实现逻辑

通过三次自连接,将当前行与前两行进行比较:

SELECT DISTINCT a.num AS ConsecutiveNums
FROM Logs a
JOIN Logs b ON a.id = b.id + 1
JOIN Logs c ON a.id = c.id + 2
WHERE a.num = b.num AND b.num = c.num;
执行流程

以示例数据为例:

  1. 连接条件

  • a.id = b.id + 1 → 当前行与前一行
  • a.id = c.id + 2 → 当前行与前两行
  1. 过滤条件:三个连续行的num相同

  2. 去重处理:使用DISTINCT避免重复结果

方法二:窗口函数法(推荐)

实现逻辑

使用LAG()窗口函数获取前两行数据:

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 sub
WHERE num = prev1 AND prev1 = prev2;
执行流程
  1. 子查询

  • LAG(num, 1)获取前一行的num
  • LAG(num, 2)获取前两行的num
  1. 过滤条件:当前行与前两行num相同

  2. 去重处理:使用DISTINCT确保唯一结果

四、两种方法对比

维度自连接法窗口函数法
代码复杂度★★★☆☆★★☆☆☆
执行效率低(需三次表扫描)高(单次扫描)
可读性较低(需理解自连接逻辑)高(直观的前向引用)
适用场景旧版本数据库(如 MySQL 5.x)现代数据库(MySQL 8.0+)

推荐场景

  • 优先使用窗口函数法(简洁高效)

  • 若数据库不支持窗口函数,使用自连接法

五、扩展优化

动态处理任意连续次数

将固定的 3 次改为变量N

CREATE FUNCTION getConsecutiveNums(N INT) RETURNS TABLE
RETURN
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 sub
WHERE num = prev1 AND prev1 = prev2;

处理更长连续次数

对于连续 5 次的情况,只需增加更多LAG()调用:

SELECT DISTINCT num
FROM (
    SELECT 
        num,
        LAG(num, 1) OVER (ORDER BY id) AS prev1,
        LAG(num, 2) OVER (ORDER BY id) AS prev2,
        LAG(num, 3) OVER (ORDER BY id) AS prev3,
        LAG(num, 4) OVER (ORDER BY id) AS prev4
    FROM Logs
) AS sub
WHERE num = prev1 AND prev1 = prev2 
  AND prev2 = prev3 AND prev3 = prev4;

六、测试用例验证

测试用例 1:正常情况

输入

INSERT INTO Logs (num) VALUES
('1'),('1'),('1'),('2'),('1'),('2'),('2');

预期输出

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

测试用例 2:多个连续数字

输入

INSERT INTO Logs (num) VALUES
('5'),('5'),('5'),('5'),('3'),('3'),('3');

预期输出

+-----------------+
| ConsecutiveNums |
+-----------------+
| 5               |
| 3               |
+-----------------+

测试用例 3:边界情况

输入

INSERT INTO Logs (num) VALUES
('a'),('a'),('a'),('a');

预期输出

+-----------------+
| ConsecutiveNums |
+-----------------+
| a               |
+-----------------+

七、常见问题解答

Q:为什么需要使用DISTINCT
A:防止同一数字多次出现在结果中(例如连续 4 次会产生两条记录)。

Q:如果连续次数超过 3 次会怎样?
A:会被正确识别,因为只要存在至少连续 3 次即可。

Q:如何处理非常大的表?
A:为id字段添加索引,提升窗口函数性能。

八、总结

  • 核心逻辑:通过比较当前行与前两行的值,判断是否连续相同。

  • 关键技巧

    • 自连接法:适用于所有数据库版本

    • 窗口函数法:简洁高效,推荐使用

  • 扩展应用

    • 动态处理任意连续次数

    • 处理更复杂的业务场景(如连续登录天数)

感谢各位的阅读,后续将持续给大家讲解力扣中的算法题和数据库题,如果觉得这篇内容对你有帮助,别忘了点赞和关注,后续还有更多精彩的算法解析与你分享!


http://www.kler.cn/a/612951.html

相关文章:

  • 提示词应用:IT模拟面试
  • CSS学习笔记5——渐变属性+盒子模型阶段案例
  • 构建高可用性西门子Camstar服务守护者:异常监控与自愈实践
  • k近邻算法K-Nearest Neighbors(KNN)
  • office_word中使用宏以及DeepSeek
  • 如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用
  • Redis原理:setnx
  • 基于深度学习的图像超分辨率技术研究与实现
  • 解决 Apache Kylin 加载 Hive 表失败的问题:深入分析与解决方案
  • 逗万DareWorks|创意重构书写美学,引领新潮无界的文创革命
  • 从物理学到机器学习:用技术手段量化分析职场被动攻击行为
  • 配置完nfs后vmware虚拟机下ubuntu/无法联网问题
  • 生成信息提取的大型语言模型综述
  • 看懂roslunch输出
  • Neo4j【环境部署 03】插件APOC和ALGO配置使用实例分享(网盘分享3.5.5兼容版本插件)
  • Python 爬虫案例
  • 在Windows下VSCodeSSH远程登录到Ubuntu
  • Java EE——线程状态
  • 手机抓取崩溃的log日志(安卓/ios)
  • C笔记20250325