链表重排序(奇数节点升序、偶数节点降序)

120 阅读2分钟

之前遇到的一个面试题,简单记录下

题目描述:

给定一个链表,它的奇数位按升序排列、偶数位降序排列,要求对链表重新排序使其整体按升序排列;特别的:只允许使用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 跑通还是有难度的。