【SQL】连续座位/得分问题--以LeetCode数据库603连续空余座位和3140连续空余座位II为例

发布于:2025-09-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、业务场景

求球队的比分;连续的空余座位;连续点击三次的用户数,中间不能有别人的点击等

二、解题思路

连续座位/得分与连续登陆的区别是,连续登陆是以同一用户为线索查看连续日期,连续得分/座位是以时间/座位号为线索,查看得分/座位空余的连续性。

首先使用窗口函数对球队得分、球员得分/座位状态/总点击数、用户点击数进行排序,然后构建辅助列求两者之间的差,最后按照相同的差值分组,筛选符合条件的座位号/得分等。

三、例题

例题链接:603. 连续空余座位 - 力扣(LeetCode)

1.题目描述

表: Cinema

+-------------+------+
| Column Name | Type |
+-------------+------+
| seat_id     | int  |
| free        | bool |
+-------------+------+
Seat_id 是该表的自动递增主键列。
在 PostgreSQL 中,free存储为整数。请使用 ::boolean将其转换为布尔格式。
该表的每一行表示第 i 个座位是否空闲。1 表示空闲,0 表示被占用。

查找电影院所有连续可用的座位。返回按 seat_id 升序排序 的结果表。测试用例的生成使得两个以上的座位连续可用。结果表格式如下所示。

输入: 
Cinema 表:
+---------+------+
| seat_id | free |
+---------+------+
| 1       | 1    |
| 2       | 0    |
| 3       | 1    |
| 4       | 1    |
| 5       | 1    |
+---------+------+
输出: 
+---------+
| seat_id |
+---------+
| 3       |
| 4       |
| 5       |
+---------+

2.解题思路

1️⃣排除占用座位使用row_number()进行排序

select seat_id,free,row_number()over() rn
from cinema
where free=1

2️⃣构建辅助列seat_id-rn

select seat_id,free,seat_id-rn as k
from (
    select seat_id,free,row_number()over() rn 
    from cinema 
    where free=1
) t

此时输出结果如下:

3️⃣题目要求返回2个以上的连续座位,也就是要筛选以k为分组数量大于1的k对应的seat_id

with a as(
    select seat_id,free,seat_id-rn as k
from (
    select seat_id,free,row_number()over() rn 
    from cinema 
    where free=1
) t)
select seat_id
from a 
where k in (
            select k 
            from a 
            group by k 
            having count(*)>1)

3.完整代码

可以把构造差值辅助列和row_number合成一步看起来简洁一点。

with a as(
    select seat_id,seat_id-row_number()over() as k
    from cinema
    where free=1
)
select seat_id
from a
where k in(
        select k
        from a
        group by k
        having count(*)>1)

四、拓展

例题链接3140. 连续空余座位 II - 力扣(LeetCode)

1.题目描述

表:Cinema

+-------------+------+
| Column Name | Type |
+-------------+------+
| seat_id     | int  |
| free        | bool |
+-------------+------+
seat_id 是这张表中的自增列。
这张表的每一行表示第 i 个作为是否空余。1 表示空余,而 0 表示被占用。

编写一个解决方案来找到电影院中 最长的空余座位 的 长度

注意:

  • 保证 最多有一个 最长连续序列。
  • 如果有 多个 相同长度 的连续序列,将它们全部输出。

返回结果表以 first_seat_id 升序排序。结果表的格式如下所示。

输入:

+---------+------+
| seat_id | free |
+---------+------+
| 1       | 1    |
| 2       | 0    |
| 3       | 1    |
| 4       | 1    |
| 5       | 1    |
+---------+------+
输出:
+-----------------+----------------+-----------------------+
| first_seat_id   | last_seat_id   | consecutive_seats_len |
+-----------------+----------------+-----------------------+
| 3               | 5              | 3                     |
+-----------------+----------------+-----------------------+

2.解题思路

1️⃣本题目是在上一题的基础上作出更具体的要求,所以第一步还是先构建辅助列标记空闲座位。但是这一步并不需要求出连续座位数了,只要给空闲座位做好标记即可。

with a as(
    select seat_id,seat_id-row_number()over() as k
    from cinema
    where free=1
)

2️⃣题目要求返回起止座位号和连续长度,并且要找到最长的长度。首先计算起止座位号和长度,然后给长度降序排序,因为要求相同长度的全部输出,使用dense_rank(),最长的序号为1。

select 
min(seat_id) first_seat_id,
max(seat_id) last_seat_id,
count(*) as consecutive_seats_len,
dense_rank()over(order by count(*) desc) rk
from b
group by k

3️⃣筛选连续长度最长的起止座位号和长度

select 
first_seat_id,
last_seat_id,
consecutive_seats_len
from(
    select 
    min(seat_id) first_seat_id,
    max(seat_id) last_seat_id,
    count(*) as consecutive_seats_len,
    dense_rank()over(order by count(*) desc) rk
    from b
    group by k) t
wwhere rk=1
order by first_seat_id

3.完整代码

#构建差值辅助列标记空闲座位
with a as(
    select seat_id,(seat_id-row_number()over()) k
    from cinema
    where free=1
),
#求连续座位长度并排序
b as (
    select 
    min(seat_id) first_seat_id,
    max(seat_id) last_seat_id,
    count(*) consecutive_seats_len,
    dense_rank()over(order by count(*) desc) rk
    from a
    group by k
)
#筛选结果
select first_seat_id,last_seat_id,consecutive_seats_len
from b
where rk=1
order by first_seat_id

五、类似练习题目:

1285. 找到连续区间的开始和结束数字 - 力扣(LeetCode)

601. 体育馆的人流量 - 力扣(LeetCode)


网站公告

今日签到

点亮在社区的每一天
去签到