LeetCode第177题_第N高的薪水

LeetCode 第177题:第N高的薪水

题目描述

编写一个 SQL 查询,获取 Employee 表中第 n 高的薪水(Salary)。

+-------------+------+
| Column Name | Type |
+-------------+------+
| id          | int  |
| salary      | int  |
+-------------+------+
id 是这个表的主键。
表的每一行包含员工的工资信息。

例如,给定上表,如果 n = 2,则应该返回第二高的薪水。如果没有第 n 高的薪水,那么查询应返回 null

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例1:

输入: 
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1  | 100    |
| 2  | 200    |
| 3  | 300    |
+----+--------+
n = 2
输出: 
+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| 200                    |
+------------------------+

示例2:

输入: 
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1  | 100    |
+----+--------+
n = 2
输出: 
+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| null                   |
+------------------------+

提示

  • 如果没有第 n 高的薪水,查询应返回 null

解题思路

方法一:使用 DENSE_RANK() 窗口函数

MySQL 中可以使用窗口函数 DENSE_RANK() 来为每一行分配一个排名,然后筛选出排名为 n 的行。

关键点:

  1. 使用 DENSE_RANK() 函数对薪水进行降序排名
  2. 筛选出排名恰好等于 n 的行
  3. 使用子查询确保在没有第 n 高薪水时返回 NULL

时间复杂度:O(n log n),其中 n 是 Employee 表中的行数(排序的时间复杂度)
空间复杂度:O(n)

方法二:使用 ORDER BY 和 LIMIT 子句

类似于第二高薪水的解法,我们可以使用 ORDER BY 对薪水进行降序排序,然后使用 LIMIT 和 OFFSET 来获取第 n 高的薪水。

关键点:

  1. 使用 DISTINCT 去除重复值
  2. 对薪水进行降序排序
  3. 使用 LIMIT 1 OFFSET (n-1) 获取第 n 条记录
  4. 在存储过程中需要特别注意 n-1 的计算

时间复杂度:O(n log n),其中 n 是 Employee 表中的行数(排序的时间复杂度)
空间复杂度:O(n)

代码实现

SQL 实现(方法一:DENSE_RANK() 窗口函数)

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  RETURN (
      SELECT 
          DISTINCT salary
      FROM 
          (SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
          FROM Employee) AS ranked
      WHERE rnk = N
  );
END

SQL 实现(方法二:ORDER BY 和 LIMIT)

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  DECLARE M INT;
  SET M = N - 1;
  RETURN (
      SELECT 
          DISTINCT salary
      FROM 
          Employee
      ORDER BY 
          salary DESC
      LIMIT 1 OFFSET M
  );
END

性能分析

各SQL实现的性能对比:

实现方法执行用时内存消耗特点
方法一459 ms0B使用窗口函数,代码简洁
方法二387 ms0B使用OFFSET,性能较好

补充说明

代码亮点

  1. 方法一使用 DENSE_RANK() 窗口函数处理排名问题,语义明确
  2. 方法二通过变量声明和赋值处理 OFFSET 参数,避免了直接在 LIMIT 语句中进行计算
  3. 两种方法都使用 DISTINCT 去除重复的薪水值

窗口函数与传统方法的区别

窗口函数的优势:

  1. 直观性:窗口函数使得排名、计算移动平均等操作更加直观
  2. 表达力:能够在单个查询中完成复杂的分析任务
  3. 性能:某些场景下比子查询和自连接更高效

传统方法的优势:

  1. 兼容性:在不支持窗口函数的数据库中也能使用
  2. 简单场景:对于简单的查询,传统方法可能更容易理解和维护

常见错误

  1. 在方法二中忘记声明中间变量 M 并设置为 N-1,导致 OFFSET 参数不正确
  2. 忘记处理重复薪水的情况
  3. 没有返回 NULL 当不存在第 n 高的薪水时
  4. 在 DENSE_RANK() 和 RANK() 之间选择错误,RANK() 会跳过重复的排名

相关题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值