每个公司的薪水中位数:奇偶数一个公式搞定
LeetCode 569 · 中位数、ROW_NUMBER、窗口计数
面试怎么回答
我会用 ROW_NUMBER 按公司分区、薪水排序编号,再用 COUNT(*) OVER 拿每家公司人数,取编号在 FLOOR((cnt+1)/2) 和 FLOOR((cnt+2)/2) 之间的行,奇偶都能覆盖。要中位数的值就再对这几行求 AVG。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
员工表有员工、公司和薪水,求每个公司薪水的中位数所在的员工记录(人数为偶数时返回中间两条)。
表结构
- Employee:Id(主键)、Company、Salary
思路
按公司分区、薪水排序给每行编号,同时用窗口 COUNT 拿到公司人数 cnt。中位数的位置是 FLOOR((cnt+1)/2) 和 FLOOR((cnt+2)/2):奇数时两者相等,只取中间一条;偶数时正好是中间两条。
参考解法
select Id,Company,Salary
from (
select Id,Company,Salary,
ROW_NUMBER() over(partition by Company order by Salary) rk,
count(*) over(partition by Company) cnt
from Employee
)t1
where rk IN (FLOOR((cnt + 1)/2), FLOOR((cnt + 2)/2))
易错点
- 用 RANK/DENSE_RANK 编号,薪水相同时编号重复,位置就对不上了,必须用 ROW_NUMBER。
- 如果要的是中位数「值」,偶数时还要对中间两条求平均。