跳转至

3124. 查找最长的电话 🔒

题目描述

表:Contacts

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| first_name  | varchar |
| last_name   | varchar |
+-------------+---------+
id 是这张表的主键(有不同值的列)。
id 是 Calls 表的外键(引用列)。
这张表的每一行都包含 id,first_name 和 last_name。

表:Calls

+-------------+------+
| Column Name | Type |
+-------------+------+
| contact_id  | int  |
| type        | enum |
| duration    | int  |
+-------------+------+
(contact_id, type, duration) 是这张表的主键(有不同值的列)。
type 字段是 ('incoming', 'outgoing') 的 ENUM (category)。
这张表的每一行包含有 calls, 包括 contact_id,type 和以秒为单位的 duration 的信息。

编写一个解决方案来找到 三个最长的呼入 和 呼出 电话。

返回结果表,以 typeduration 和 first_name 降序排序 ,duration 的格式必须为 HH:MM:SS

结果格式如下所示。

 

示例 1:

输入:

Contacts 表:

+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
| 1  | John       | Doe       |
| 2  | Jane       | Smith     |
| 3  | Alice      | Johnson   |
| 4  | Michael    | Brown     |
| 5  | Emily      | Davis     |
+----+------------+-----------+        

Calls 表:

+------------+----------+----------+
| contact_id | type     | duration |
+------------+----------+----------+
| 1          | incoming | 120      |
| 1          | outgoing | 180      |
| 2          | incoming | 300      |
| 2          | outgoing | 240      |
| 3          | incoming | 150      |
| 3          | outgoing | 360      |
| 4          | incoming | 420      |
| 4          | outgoing | 200      |
| 5          | incoming | 180      |
| 5          | outgoing | 280      |
+------------+----------+----------+
        

输出:

+-----------+----------+-------------------+
| first_name| type     | duration_formatted|
+-----------+----------+-------------------+
| Michael   | incoming | 00:07:00          |
| Jane      | incoming | 00:05:00          |
| Emily     | incoming | 00:03:00          |
| Alice     | outgoing | 00:06:00          |
| Emily     | outgoing | 00:04:40          |
| Jane      | outgoing | 00:04:00          |
+-----------+----------+-------------------+
        

解释:

  • Michael 有一通长达 7 分钟的呼入电话。
  • Jane 有一通长达 5 分钟的呼入电话。
  • Emily 有一通长达 3 分钟的呼入电话。
  • Alice 有一通长达 6 分钟的呼出电话。
  • Emily 有一通长达 4 分 40 秒的呼出电话。
  • Jane 有一通长达 4 分钟的呼出电话。

注意:输出表以 type,duration 和 first_name 降序排序。

解法

方法一:等值连接 + 窗口函数

我们可以使用等值连接将两张表连接起来,然后使用窗口函数 RANK() 计算每个类型的电话的排名。最后,我们只需要筛选出排名前三的电话即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
WITH
    T AS (
        SELECT
            first_name,
            type,
            DATE_FORMAT(SEC_TO_TIME(duration), "%H:%i:%s") AS duration_formatted,
            RANK() OVER (
                PARTITION BY type
                ORDER BY duration DESC
            ) AS rk
        FROM
            Calls AS c1
            JOIN Contacts AS c2 ON c1.contact_id = c2.id
    )
SELECT
    first_name,
    type,
    duration_formatted
FROM T
WHERE rk <= 3
ORDER BY 2, 3 DESC, 1 DESC;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd


def find_longest_calls(contacts: pd.DataFrame, calls: pd.DataFrame) -> pd.DataFrame:
    merged_data = calls.merge(contacts, left_on="contact_id", right_on="id")
    merged_data["duration_formatted"] = (
        merged_data["duration"] // 3600 * 10000
        + merged_data["duration"] % 3600 // 60 * 100
        + merged_data["duration"] % 60
    ).apply(lambda x: "{:02}:{:02}:{:02}".format(x // 10000, x // 100 % 100, x % 100))

    merged_data["rk"] = merged_data.groupby("type")["duration"].rank(
        method="dense", ascending=False
    )

    result = merged_data[merged_data["rk"] <= 3][
        ["first_name", "type", "duration_formatted"]
    ]
    result = result.sort_values(
        by=["type", "duration_formatted", "first_name"], ascending=[True, False, False]
    )
    return result

评论