diff --git a/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README.md b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README.md new file mode 100644 index 0000000000000..9ece3baa11e91 --- /dev/null +++ b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README.md @@ -0,0 +1,427 @@ +--- +comments: true +difficulty: 困难 +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README.md +tags: + - 数据库 +--- + + + +# [3617. Find Students with Study Spiral Pattern](https://leetcode.cn/problems/find-students-with-study-spiral-pattern) + +[English Version](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README_EN.md) + +## 题目描述 + + + +

Table: students

+ +
++--------------+---------+
+| Column Name  | Type    |
++--------------+---------+
+| student_id   | int     |
+| student_name | varchar |
+| major        | varchar |
++--------------+---------+
+student_id is the unique identifier for this table.
+Each row contains information about a student and their academic major.
+
+ +

Table: study_sessions

+ +
++---------------+---------+
+| Column Name   | Type    |
++---------------+---------+
+| session_id    | int     |
+| student_id    | int     |
+| subject       | varchar |
+| session_date  | date    |
+| hours_studied | decimal |
++---------------+---------+
+session_id is the unique identifier for this table.
+Each row represents a study session by a student for a specific subject.
+
+ +

Write a solution to find students who follow the Study Spiral Pattern - students who consistently study multiple subjects in a rotating cycle.

+ + + +

Return the result table ordered by cycle length in descending order, then by total study hours in descending order.

+ +

The result format is in the following example.

+ +

 

+

Example:

+ +
+

Input:

+ +

students table:

+ +
++------------+--------------+------------------+
+| student_id | student_name | major            |
++------------+--------------+------------------+
+| 1          | Alice Chen   | Computer Science |
+| 2          | Bob Johnson  | Mathematics      |
+| 3          | Carol Davis  | Physics          |
+| 4          | David Wilson | Chemistry        |
+| 5          | Emma Brown   | Biology          |
++------------+--------------+------------------+
+
+ +

study_sessions table:

+ +
++------------+------------+------------+--------------+---------------+
+| session_id | student_id | subject    | session_date | hours_studied |
++------------+------------+------------+--------------+---------------+
+| 1          | 1          | Math       | 2023-10-01   | 2.5           |
+| 2          | 1          | Physics    | 2023-10-02   | 3.0           |
+| 3          | 1          | Chemistry  | 2023-10-03   | 2.0           |
+| 4          | 1          | Math       | 2023-10-04   | 2.5           |
+| 5          | 1          | Physics    | 2023-10-05   | 3.0           |
+| 6          | 1          | Chemistry  | 2023-10-06   | 2.0           |
+| 7          | 2          | Algebra    | 2023-10-01   | 4.0           |
+| 8          | 2          | Calculus   | 2023-10-02   | 3.5           |
+| 9          | 2          | Statistics | 2023-10-03   | 2.5           |
+| 10         | 2          | Geometry   | 2023-10-04   | 3.0           |
+| 11         | 2          | Algebra    | 2023-10-05   | 4.0           |
+| 12         | 2          | Calculus   | 2023-10-06   | 3.5           |
+| 13         | 2          | Statistics | 2023-10-07   | 2.5           |
+| 14         | 2          | Geometry   | 2023-10-08   | 3.0           |
+| 15         | 3          | Biology    | 2023-10-01   | 2.0           |
+| 16         | 3          | Chemistry  | 2023-10-02   | 2.5           |
+| 17         | 3          | Biology    | 2023-10-03   | 2.0           |
+| 18         | 3          | Chemistry  | 2023-10-04   | 2.5           |
+| 19         | 4          | Organic    | 2023-10-01   | 3.0           |
+| 20         | 4          | Physical   | 2023-10-05   | 2.5           |
++------------+------------+------------+--------------+---------------+
+
+ +

Output:

+ +
++------------+--------------+------------------+--------------+-------------------+
+| student_id | student_name | major            | cycle_length | total_study_hours |
++------------+--------------+------------------+--------------+-------------------+
+| 2          | Bob Johnson  | Mathematics      | 4            | 26.0              |
+| 1          | Alice Chen   | Computer Science | 3            | 15.0              |
++------------+--------------+------------------+--------------+-------------------+
+
+ +

Explanation:

+ + + +

The result table is ordered by cycle_length in descending order, then by total_study_hours in descending order.

+
+ + + +## 解法 + + + +### 方法一 + + + +#### MySQL + +```sql +# Write your MySQL query statement below +WITH + -- 第一步:为每个学生的学习记录按照日期排序并编号 + ranked_sessions AS ( + SELECT + s.student_id, + ss.session_date, + ss.subject, + ss.hours_studied, + ROW_NUMBER() OVER ( + PARTITION BY s.student_id + ORDER BY ss.session_date + ) AS rn + FROM + study_sessions ss + JOIN students s ON s.student_id = ss.student_id + ), + -- 第二步:计算当前学习日期与前一次学习的日期差 + grouped_sessions AS ( + SELECT + *, + DATEDIFF( + session_date, + LAG(session_date) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) + ) AS date_diff + FROM ranked_sessions + ), + -- 第三步:将学习记录按照日期差是否大于2进行分组(连续段) + session_groups AS ( + SELECT + *, + SUM( + CASE + WHEN date_diff > 2 + OR date_diff IS NULL THEN 1 + ELSE 0 + END + ) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) AS group_id + FROM grouped_sessions + ), + -- 第四步:筛选出每个学生的每个连续学习段中包含至少6次学习的序列 + valid_sequences AS ( + SELECT + student_id, + group_id, + COUNT(*) AS session_count, + GROUP_CONCAT(subject ORDER BY session_date) AS subject_sequence, + SUM(hours_studied) AS total_hours + FROM session_groups + GROUP BY student_id, group_id + HAVING session_count >= 6 + ), + -- 第五步:检测是否存在重复的科目循环模式 + pattern_detected AS ( + SELECT + vs.student_id, + vs.total_hours, + vs.subject_sequence, + COUNT( + DISTINCT + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', n), ',', -1) + ) AS cycle_length + FROM + valid_sequences vs + JOIN ( + -- 生成1到100的数字,用于提取第n个科目 + SELECT a.N + b.N * 10 + 1 AS n + FROM + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) a, + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) b + ) nums + ON n <= 10 + WHERE + -- 简化匹配:检查前半段和后半段是否相同(即是否重复) + LENGTH(subject_sequence) > 0 + AND LOCATE(',', subject_sequence) > 0 + AND ( + -- 匹配3科循环2轮的模式 + subject_sequence LIKE CONCAT( + SUBSTRING_INDEX(subject_sequence, ',', 3), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 6), ',', -3), + '%' + ) + OR subject_sequence LIKE CONCAT( -- 匹配4科循环2轮的模式 + SUBSTRING_INDEX(subject_sequence, ',', 4), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 8), ',', -4), + '%' + ) + ) + GROUP BY vs.student_id, vs.total_hours, vs.subject_sequence + ), + -- 第六步:拼接学生基本信息,并过滤掉循环长度小于3的结果 + final_output AS ( + SELECT + s.student_id, + s.student_name, + s.major, + pd.cycle_length, + pd.total_hours AS total_study_hours + FROM + pattern_detected pd + JOIN students s ON s.student_id = pd.student_id + WHERE pd.cycle_length >= 3 + ) +-- 第七步:输出结果,并按循环长度和总学习时长降序排列 +SELECT * +FROM final_output +ORDER BY cycle_length DESC, total_study_hours DESC; +``` + +#### Pandas + +```python +import pandas as pd +from datetime import timedelta + + +def find_study_spiral_pattern( + students: pd.DataFrame, study_sessions: pd.DataFrame +) -> pd.DataFrame: + study_sessions["session_date"] = pd.to_datetime(study_sessions["session_date"]) + + result = [] + + for student_id, group in study_sessions.groupby("student_id"): + # 按日期排序 + group = group.sort_values("session_date").reset_index(drop=True) + + # 用于记录当前连续段 + temp = [] + last_date = None + + for idx, row in group.iterrows(): + if not temp: + temp.append(row) + else: + delta = (row["session_date"] - last_date).days + if delta <= 2: + temp.append(row) + else: + # 处理之前的连续段 + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + temp = [row] + last_date = row["session_date"] + + # 最后一个连续段 + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + + # 构造结果 DataFrame + df_result = pd.DataFrame( + result, columns=["student_id", "cycle_length", "total_study_hours"] + ) + + if df_result.empty: + return pd.DataFrame( + columns=[ + "student_id", + "student_name", + "major", + "cycle_length", + "total_study_hours", + ] + ) + + # 合并 student_name 和 major + df_result = df_result.merge(students, on="student_id") + + df_result = df_result[ + ["student_id", "student_name", "major", "cycle_length", "total_study_hours"] + ] + + return df_result.sort_values( + by=["cycle_length", "total_study_hours"], ascending=[False, False] + ).reset_index(drop=True) + + +def _check_pattern(student_id, sessions, result): + subjects = [row["subject"] for row in sessions] + hours = sum(row["hours_studied"] for row in sessions) + + n = len(subjects) + for cycle_len in range(3, n // 2 + 1): + if n % cycle_len != 0: + continue + first_cycle = subjects[:cycle_len] + is_pattern = True + for i in range(1, n // cycle_len): + if subjects[i * cycle_len : (i + 1) * cycle_len] != first_cycle: + is_pattern = False + break + if is_pattern: + result.append( + { + "student_id": student_id, + "cycle_length": cycle_len, + "total_study_hours": hours, + } + ) + break # 只记录最长周期的第一个匹配 +``` + + + + + + diff --git a/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README_EN.md b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README_EN.md new file mode 100644 index 0000000000000..00bc4140329ff --- /dev/null +++ b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/README_EN.md @@ -0,0 +1,430 @@ +--- +comments: true +difficulty: Hard +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README_EN.md +tags: + - Database +--- + + + +# [3617. Find Students with Study Spiral Pattern](https://leetcode.com/problems/find-students-with-study-spiral-pattern) + +[中文文档](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README.md) + +## Description + + + +

Table: students

+ +
++--------------+---------+
+| Column Name  | Type    |
++--------------+---------+
+| student_id   | int     |
+| student_name | varchar |
+| major        | varchar |
++--------------+---------+
+student_id is the unique identifier for this table.
+Each row contains information about a student and their academic major.
+
+ +

Table: study_sessions

+ +
++---------------+---------+
+| Column Name   | Type    |
++---------------+---------+
+| session_id    | int     |
+| student_id    | int     |
+| subject       | varchar |
+| session_date  | date    |
+| hours_studied | decimal |
++---------------+---------+
+session_id is the unique identifier for this table.
+Each row represents a study session by a student for a specific subject.
+
+ +

Write a solution to find students who follow the Study Spiral Pattern - students who consistently study multiple subjects in a rotating cycle.

+ + + +

Return the result table ordered by cycle length in descending order, then by total study hours in descending order.

+ +

The result format is in the following example.

+ +

 

+

Example:

+ +
+

Input:

+ +

students table:

+ +
++------------+--------------+------------------+
+| student_id | student_name | major            |
++------------+--------------+------------------+
+| 1          | Alice Chen   | Computer Science |
+| 2          | Bob Johnson  | Mathematics      |
+| 3          | Carol Davis  | Physics          |
+| 4          | David Wilson | Chemistry        |
+| 5          | Emma Brown   | Biology          |
++------------+--------------+------------------+
+
+ +

study_sessions table:

+ +
++------------+------------+------------+--------------+---------------+
+| session_id | student_id | subject    | session_date | hours_studied |
++------------+------------+------------+--------------+---------------+
+| 1          | 1          | Math       | 2023-10-01   | 2.5           |
+| 2          | 1          | Physics    | 2023-10-02   | 3.0           |
+| 3          | 1          | Chemistry  | 2023-10-03   | 2.0           |
+| 4          | 1          | Math       | 2023-10-04   | 2.5           |
+| 5          | 1          | Physics    | 2023-10-05   | 3.0           |
+| 6          | 1          | Chemistry  | 2023-10-06   | 2.0           |
+| 7          | 2          | Algebra    | 2023-10-01   | 4.0           |
+| 8          | 2          | Calculus   | 2023-10-02   | 3.5           |
+| 9          | 2          | Statistics | 2023-10-03   | 2.5           |
+| 10         | 2          | Geometry   | 2023-10-04   | 3.0           |
+| 11         | 2          | Algebra    | 2023-10-05   | 4.0           |
+| 12         | 2          | Calculus   | 2023-10-06   | 3.5           |
+| 13         | 2          | Statistics | 2023-10-07   | 2.5           |
+| 14         | 2          | Geometry   | 2023-10-08   | 3.0           |
+| 15         | 3          | Biology    | 2023-10-01   | 2.0           |
+| 16         | 3          | Chemistry  | 2023-10-02   | 2.5           |
+| 17         | 3          | Biology    | 2023-10-03   | 2.0           |
+| 18         | 3          | Chemistry  | 2023-10-04   | 2.5           |
+| 19         | 4          | Organic    | 2023-10-01   | 3.0           |
+| 20         | 4          | Physical   | 2023-10-05   | 2.5           |
++------------+------------+------------+--------------+---------------+
+
+ +

Output:

+ +
++------------+--------------+------------------+--------------+-------------------+
+| student_id | student_name | major            | cycle_length | total_study_hours |
++------------+--------------+------------------+--------------+-------------------+
+| 2          | Bob Johnson  | Mathematics      | 4            | 26.0              |
+| 1          | Alice Chen   | Computer Science | 3            | 15.0              |
++------------+--------------+------------------+--------------+-------------------+
+
+ +

Explanation:

+ + + +

The result table is ordered by cycle_length in descending order, then by total_study_hours in descending order.

+
+ + + +## Solutions + + + +### Solution 1 + + + +#### MySQL + +```sql +# Write your MySQL query statement below +WITH + ranked_sessions AS ( + SELECT + s.student_id, + ss.session_date, + ss.subject, + ss.hours_studied, + ROW_NUMBER() OVER ( + PARTITION BY s.student_id + ORDER BY ss.session_date + ) AS rn + FROM + study_sessions ss + JOIN students s ON s.student_id = ss.student_id + ), + grouped_sessions AS ( + SELECT + *, + DATEDIFF( + session_date, + LAG(session_date) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) + ) AS date_diff + FROM ranked_sessions + ), + session_groups AS ( + SELECT + *, + SUM( + CASE + WHEN date_diff > 2 + OR date_diff IS NULL THEN 1 + ELSE 0 + END + ) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) AS group_id + FROM grouped_sessions + ), + valid_sequences AS ( + SELECT + student_id, + group_id, + COUNT(*) AS session_count, + GROUP_CONCAT(subject ORDER BY session_date) AS subject_sequence, + SUM(hours_studied) AS total_hours + FROM session_groups + GROUP BY student_id, group_id + HAVING session_count >= 6 + ), + pattern_detected AS ( + SELECT + vs.student_id, + vs.total_hours, + vs.subject_sequence, + COUNT( + DISTINCT + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', n), ',', -1) + ) AS cycle_length + FROM + valid_sequences vs + JOIN ( + SELECT a.N + b.N * 10 + 1 AS n + FROM + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) a, + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) b + ) nums + ON n <= 10 + WHERE + -- Check if the sequence repeats every `k` items, for some `k >= 3` and divides session_count exactly + -- We simplify by checking the start and middle halves are equal + LENGTH(subject_sequence) > 0 + AND LOCATE(',', subject_sequence) > 0 + AND ( + -- For cycle length 3: + subject_sequence LIKE CONCAT( + SUBSTRING_INDEX(subject_sequence, ',', 3), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 6), ',', -3), + '%' + ) + OR subject_sequence LIKE CONCAT( + -- For cycle length 4: + SUBSTRING_INDEX(subject_sequence, ',', 4), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 8), ',', -4), + '%' + ) + ) + GROUP BY vs.student_id, vs.total_hours, vs.subject_sequence + ), + final_output AS ( + SELECT + s.student_id, + s.student_name, + s.major, + pd.cycle_length, + pd.total_hours AS total_study_hours + FROM + pattern_detected pd + JOIN students s ON s.student_id = pd.student_id + WHERE pd.cycle_length >= 3 + ) +SELECT * +FROM final_output +ORDER BY cycle_length DESC, total_study_hours DESC; +``` + +#### Pandas + +```python +import pandas as pd +from datetime import timedelta + + +def find_study_spiral_pattern( + students: pd.DataFrame, study_sessions: pd.DataFrame +) -> pd.DataFrame: + # Convert session_date to datetime + study_sessions["session_date"] = pd.to_datetime(study_sessions["session_date"]) + + result = [] + + # Group study sessions by student + for student_id, group in study_sessions.groupby("student_id"): + # Sort sessions by date + group = group.sort_values("session_date").reset_index(drop=True) + + temp = [] # Holds current contiguous segment + last_date = None + + for idx, row in group.iterrows(): + if not temp: + temp.append(row) + else: + delta = (row["session_date"] - last_date).days + if delta <= 2: + temp.append(row) + else: + # Check the previous contiguous segment + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + temp = [row] + last_date = row["session_date"] + + # Check the final segment + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + + # Build result DataFrame + df_result = pd.DataFrame( + result, columns=["student_id", "cycle_length", "total_study_hours"] + ) + + if df_result.empty: + return pd.DataFrame( + columns=[ + "student_id", + "student_name", + "major", + "cycle_length", + "total_study_hours", + ] + ) + + # Join with students table to get name and major + df_result = df_result.merge(students, on="student_id") + + df_result = df_result[ + ["student_id", "student_name", "major", "cycle_length", "total_study_hours"] + ] + + return df_result.sort_values( + by=["cycle_length", "total_study_hours"], ascending=[False, False] + ).reset_index(drop=True) + + +def _check_pattern(student_id, sessions, result): + subjects = [row["subject"] for row in sessions] + hours = sum(row["hours_studied"] for row in sessions) + + n = len(subjects) + + # Try possible cycle lengths from 3 up to half of the sequence + for cycle_len in range(3, n // 2 + 1): + if n % cycle_len != 0: + continue + + # Extract the first cycle + first_cycle = subjects[:cycle_len] + is_pattern = True + + # Compare each following cycle with the first + for i in range(1, n // cycle_len): + if subjects[i * cycle_len : (i + 1) * cycle_len] != first_cycle: + is_pattern = False + break + + # If a repeated cycle is detected, store the result + if is_pattern: + result.append( + { + "student_id": student_id, + "cycle_length": cycle_len, + "total_study_hours": hours, + } + ) + break # Stop at the first valid cycle found +``` + + + + + + diff --git a/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.py b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.py new file mode 100644 index 0000000000000..d01704a9c4eb3 --- /dev/null +++ b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.py @@ -0,0 +1,97 @@ +import pandas as pd +from datetime import timedelta + + +def find_study_spiral_pattern( + students: pd.DataFrame, study_sessions: pd.DataFrame +) -> pd.DataFrame: + # Convert session_date to datetime + study_sessions["session_date"] = pd.to_datetime(study_sessions["session_date"]) + + result = [] + + # Group study sessions by student + for student_id, group in study_sessions.groupby("student_id"): + # Sort sessions by date + group = group.sort_values("session_date").reset_index(drop=True) + + temp = [] # Holds current contiguous segment + last_date = None + + for idx, row in group.iterrows(): + if not temp: + temp.append(row) + else: + delta = (row["session_date"] - last_date).days + if delta <= 2: + temp.append(row) + else: + # Check the previous contiguous segment + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + temp = [row] + last_date = row["session_date"] + + # Check the final segment + if len(temp) >= 6: + _check_pattern(student_id, temp, result) + + # Build result DataFrame + df_result = pd.DataFrame( + result, columns=["student_id", "cycle_length", "total_study_hours"] + ) + + if df_result.empty: + return pd.DataFrame( + columns=[ + "student_id", + "student_name", + "major", + "cycle_length", + "total_study_hours", + ] + ) + + # Join with students table to get name and major + df_result = df_result.merge(students, on="student_id") + + df_result = df_result[ + ["student_id", "student_name", "major", "cycle_length", "total_study_hours"] + ] + + return df_result.sort_values( + by=["cycle_length", "total_study_hours"], ascending=[False, False] + ).reset_index(drop=True) + + +def _check_pattern(student_id, sessions, result): + subjects = [row["subject"] for row in sessions] + hours = sum(row["hours_studied"] for row in sessions) + + n = len(subjects) + + # Try possible cycle lengths from 3 up to half of the sequence + for cycle_len in range(3, n // 2 + 1): + if n % cycle_len != 0: + continue + + # Extract the first cycle + first_cycle = subjects[:cycle_len] + is_pattern = True + + # Compare each following cycle with the first + for i in range(1, n // cycle_len): + if subjects[i * cycle_len : (i + 1) * cycle_len] != first_cycle: + is_pattern = False + break + + # If a repeated cycle is detected, store the result + if is_pattern: + result.append( + { + "student_id": student_id, + "cycle_length": cycle_len, + "total_study_hours": hours, + } + ) + break # Stop at the first valid cycle found diff --git a/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.sql b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.sql new file mode 100644 index 0000000000000..2e14c17e3d626 --- /dev/null +++ b/solution/3600-3699/3617.Find Students with Study Spiral Pattern/Solution.sql @@ -0,0 +1,150 @@ +# Write your MySQL query statement below +WITH + ranked_sessions AS ( + SELECT + s.student_id, + ss.session_date, + ss.subject, + ss.hours_studied, + ROW_NUMBER() OVER ( + PARTITION BY s.student_id + ORDER BY ss.session_date + ) AS rn + FROM + study_sessions ss + JOIN students s ON s.student_id = ss.student_id + ), + grouped_sessions AS ( + SELECT + *, + DATEDIFF( + session_date, + LAG(session_date) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) + ) AS date_diff + FROM ranked_sessions + ), + session_groups AS ( + SELECT + *, + SUM( + CASE + WHEN date_diff > 2 + OR date_diff IS NULL THEN 1 + ELSE 0 + END + ) OVER ( + PARTITION BY student_id + ORDER BY session_date + ) AS group_id + FROM grouped_sessions + ), + valid_sequences AS ( + SELECT + student_id, + group_id, + COUNT(*) AS session_count, + GROUP_CONCAT(subject ORDER BY session_date) AS subject_sequence, + SUM(hours_studied) AS total_hours + FROM session_groups + GROUP BY student_id, group_id + HAVING session_count >= 6 + ), + pattern_detected AS ( + SELECT + vs.student_id, + vs.total_hours, + vs.subject_sequence, + COUNT( + DISTINCT + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', n), ',', -1) + ) AS cycle_length + FROM + valid_sequences vs + JOIN ( + SELECT a.N + b.N * 10 + 1 AS n + FROM + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) a, + ( + SELECT 0 AS N + UNION + SELECT 1 + UNION + SELECT 2 + UNION + SELECT 3 + UNION + SELECT 4 + UNION + SELECT 5 + UNION + SELECT 6 + UNION + SELECT 7 + UNION + SELECT 8 + UNION + SELECT 9 + ) b + ) nums + ON n <= 10 + WHERE + -- Check if the sequence repeats every `k` items, for some `k >= 3` and divides session_count exactly + -- We simplify by checking the start and middle halves are equal + LENGTH(subject_sequence) > 0 + AND LOCATE(',', subject_sequence) > 0 + AND ( + -- For cycle length 3: + subject_sequence LIKE CONCAT( + SUBSTRING_INDEX(subject_sequence, ',', 3), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 6), ',', -3), + '%' + ) + OR subject_sequence LIKE CONCAT( + -- For cycle length 4: + SUBSTRING_INDEX(subject_sequence, ',', 4), + ',', + SUBSTRING_INDEX(SUBSTRING_INDEX(subject_sequence, ',', 8), ',', -4), + '%' + ) + ) + GROUP BY vs.student_id, vs.total_hours, vs.subject_sequence + ), + final_output AS ( + SELECT + s.student_id, + s.student_name, + s.major, + pd.cycle_length, + pd.total_hours AS total_study_hours + FROM + pattern_detected pd + JOIN students s ON s.student_id = pd.student_id + WHERE pd.cycle_length >= 3 + ) +SELECT * +FROM final_output +ORDER BY cycle_length DESC, total_study_hours DESC; diff --git a/solution/DATABASE_README.md b/solution/DATABASE_README.md index 6df4c2e40eb06..6e259ae79c78a 100644 --- a/solution/DATABASE_README.md +++ b/solution/DATABASE_README.md @@ -322,6 +322,7 @@ | 3586 | [寻找 COVID 康复患者](/solution/3500-3599/3586.Find%20COVID%20Recovery%20Patients/README.md) | `数据库` | 中等 | | | 3601 | [寻找燃油效率提升的驾驶员](/solution/3600-3699/3601.Find%20Drivers%20with%20Improved%20Fuel%20Efficiency/README.md) | `数据库` | 中等 | | | 3611 | [查找超预订员工](/solution/3600-3699/3611.Find%20Overbooked%20Employees/README.md) | | 中等 | | +| 3617 | [Find Students with Study Spiral Pattern](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README.md) | | 困难 | | ## 版权 diff --git a/solution/DATABASE_README_EN.md b/solution/DATABASE_README_EN.md index d00b8d980391d..c7fe9f1d9290c 100644 --- a/solution/DATABASE_README_EN.md +++ b/solution/DATABASE_README_EN.md @@ -320,6 +320,7 @@ Press Control + F(or Command + F on | 3586 | [Find COVID Recovery Patients](/solution/3500-3599/3586.Find%20COVID%20Recovery%20Patients/README_EN.md) | `Database` | Medium | | | 3601 | [Find Drivers with Improved Fuel Efficiency](/solution/3600-3699/3601.Find%20Drivers%20with%20Improved%20Fuel%20Efficiency/README_EN.md) | `Database` | Medium | | | 3611 | [Find Overbooked Employees](/solution/3600-3699/3611.Find%20Overbooked%20Employees/README_EN.md) | | Medium | | +| 3617 | [Find Students with Study Spiral Pattern](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README_EN.md) | | Hard | | ## Copyright diff --git a/solution/README.md b/solution/README.md index b06c5cb059814..b4f539458e615 100644 --- a/solution/README.md +++ b/solution/README.md @@ -3627,6 +3627,7 @@ | 3614 | [用特殊操作处理字符串 II](/solution/3600-3699/3614.Process%20String%20with%20Special%20Operations%20II/README.md) | | 困难 | 第 458 场周赛 | | 3615 | [图中的最长回文路径](/solution/3600-3699/3615.Longest%20Palindromic%20Path%20in%20Graph/README.md) | | 困难 | 第 458 场周赛 | | 3616 | [Number of Student Replacements](/solution/3600-3699/3616.Number%20of%20Student%20Replacements/README.md) | | 中等 | 🔒 | +| 3617 | [Find Students with Study Spiral Pattern](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README.md) | | 困难 | | ## 版权 diff --git a/solution/README_EN.md b/solution/README_EN.md index 565b58ac48d8d..d2d2c23c4c4e1 100644 --- a/solution/README_EN.md +++ b/solution/README_EN.md @@ -3625,6 +3625,7 @@ Press Control + F(or Command + F on | 3614 | [Process String with Special Operations II](/solution/3600-3699/3614.Process%20String%20with%20Special%20Operations%20II/README_EN.md) | | Hard | Weekly Contest 458 | | 3615 | [Longest Palindromic Path in Graph](/solution/3600-3699/3615.Longest%20Palindromic%20Path%20in%20Graph/README_EN.md) | | Hard | Weekly Contest 458 | | 3616 | [Number of Student Replacements](/solution/3600-3699/3616.Number%20of%20Student%20Replacements/README_EN.md) | | Medium | 🔒 | +| 3617 | [Find Students with Study Spiral Pattern](/solution/3600-3699/3617.Find%20Students%20with%20Study%20Spiral%20Pattern/README_EN.md) | | Hard | | ## Copyright