之前遇到的一个面试题,简单记录下
题目描述:
给定一个链表,它的奇数位按升序排列、偶数位降序排列,要求对链表重新排序使其整体按升序排列;特别的:只允许使用O(1)的辅助空间。
样例输入:
1 8 3 6 5 4 7 2 9
样例输出:
1 2 3 4 5 6 7 8 9
代码样例:
class Node(var `val`: Int) {
var next: Node? = null
}
fun solve(head: Node): Node {
// TODO: your code here...
}
题解
思路:先将链表一分为二,奇数节点组成的子链表不动,偶数节点组成的子链表翻转;再将得到的两个有序链表合并
class Node(var `val`: Int) {
var next: Node? = null
}
fun solve(head: Node): Node {
// 1. 拆分并翻转成两个有序链表
val (h1, h2) = split(head)
// 2. 合并两个有序链表
return merge(h1, h2)
}
fun split(head: Node): Array<Node> {
// p1:奇数节点,p2:偶数节点
var p1: Node? = head
var p2: Node? = head.next
var parent: Node? = null // p2的前继节点
var grand: Node? // p2的前前继节点,即parent的前继节点
while (p1 != null || p2 != null) {
if (p1 != null) { // 移除偶数节点
p1.next = p1.next?.next
p1 = p1.next
}
if (p2 != null) { // 移除奇数节点
p2.next = p2.next?.next
grand = parent
parent = p2
p2 = p2.next
parent.next = grand // 翻转偶数节点指向
}
}
return arrayOf(head, parent!!)
}
fun merge(h1: Node?, h2: Node?): Node {
if (h1 == null || h2 == null) {
return h1 ?: h2!!
}
// p1 为头结点更小的链表
var p1: Node? = if (h1.`val` <= h2.`val`) h1 else h2
val p2: Node = if (h1.`val` <= h2.`val`) h2 else h1
// 直接拼接两个链表:p1 -> p2
var p = p1
while (p?.next != null) {
p = p.next
}
p?.next = p2
// 通过前后指针交换使得整体有序
while (p1 != null && p1 != p2) {
if (p1.`val` > p2.`val`) {
// 交换前后节点的值
p1.`val` = p2.`val`.apply { p2.`val` = p1!!.`val` }
// 交换调整后半段顺序(冒泡)
p = p2
while (p?.next != null && p!!.`val` > p.next!!.`val`) {
p.`val` = p.next!!.`val`.apply { p!!.next!!.`val` = p!!.`val` }
p = p.next
}
}
p1 = p1.next
}
return if (h1.`val` <= h2.`val`) h1 else h2
}
// ==================================== Test Case ====================================
fun main(args: Array<String>) {
val head = Node(-1)
var p: Node? = head
var a = 1
var b = 8
for (i in 1..9) {
if (i % 2 == 0) {
p?.next = Node(b)
b -= 2
} else {
p?.next = Node(a)
a += 2
}
p = p?.next
}
val h1 = solve(head.next!!)
print(h1)
}
fun print(h: Node?) {
var p = h
while (p != null) {
print("${p.`val`} ")
p = p.next
}
println()
}
笔者注:有一定代码量和调试成本,若要求仅用在线 IDE 跑通还是有难度的。