相邻同学换座位:奇偶编号互换
LeetCode 626 · CASE、LAG/LEAD、奇偶判断
面试怎么回答
我最常用的是改 id:偶数 id 减 1,奇数 id 加 1,但如果奇数 id 等于总人数就保持不变,最后 ORDER BY 新 id。用 LAG/LEAD 交换学生名也行,关键都是处理好人数为奇数时最后一个人。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
座位表的 id 连续递增,每个 id 对应一个学生。把相邻两个学生的座位互换(1 和 2 换、3 和 4 换……),如果总人数是奇数,最后一个人不动。按 id 输出新的座位安排。
表结构
- seat:id(主键,连续递增)、student
思路
有两种思路:一是改学生,偶数 id 取上一行的学生、奇数 id 取下一行的学生(最后一个奇数 id 没有下一行就保持不变),用 LAG/LEAD 实现;二是改 id,偶数 id 减 1、奇数 id 加 1,最后一个奇数 id 不变,再按新 id 排序。
参考解法
写法 1:用 LAG / LEAD 交换学生
select id,
(case when id%2=0 then f
when id%2=1 && b is not null then b
else student end) student
from(
select id,student,
lag(student,1,null) over(order by id) f,
lead(student,1,null) over(order by id) b
from seat
)t1
写法 2:直接改 id,再按新 id 排序
select
if(id%2=0,
id-1,
if(id=(select count(distinct id) from seat),
id,
id+1))
as id,student
from seat
order by id;
写法 3:异或技巧:(id-1) XOR 1 + 1 正好把 1↔2、3↔4 配对
select b.id,a.student from
seat as a,seat as b,(select count(*) as cnt from seat) as c
where b.id=1^(a.id-1)+1
-- where a.id=1^(b.id-1)+1; 也可以这样写,更容易理解
|| (c.cnt%2 && b.id=c.cnt && a.id=c.cnt);
易错点
- 忘了处理奇数人数时的最后一位,会把他换成 NULL 或换出表外。
- 第一种写法中
&&是 MySQL 语法,标准写法用 AND。