143. 重排链表

55 阅读1分钟

给定一个单链表 L **的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

image.png

输入: head = [1,2,3,4]
输出: [1,4,2,3]

示例 2:

image.png

输入: head = [1,2,3,4,5]
输出: [1,5,2,4,3]

题解:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {void} Do not return anything, modify head in-place instead.
 */
// 方法一:利用栈 
var reorderList = function (head) {
    let stack = [], tmp
    // 断掉每一条next指针
    while (head) {
        tmp = head.next;
        head.next = null;
        stack.push(head);
        head = tmp;
    }

    let i = 0, j = stack.length - 1
    while (i < j) {
        // 遍历当前值i得next指向对应j位置
        stack[i].next = stack[j];
        // 当 j != i + 1  j位置next指向i + 1位置
        j !== i + 1 && (stack[j].next = stack[i + 1]);
        i++;
        j--
    }
    return stack[0]
};

// 方法二:利用栈
var reorderList = function (head) {
    const stack = [];
    while (head) {
        stack.push(head)
        head = head.next
    }
    while (stack.length > 2) {
        let h = stack.shift()
        let t = stack.pop()
        t.next = h.next;
        h.next = t
    }
    stack[stack.length - 1].next = null
    return head

}

// 方法三:双指针 翻转插入
var reorderList = function (head) {
    if (!head.next) return head;
    let slow = head, fast = head.next;
    // slow 为第一个结点开始,fast 为第二个结点开始,
    // 这样结点总个数奇数或偶数都很好兼容
    // fast 走两步,不能一次性走两步,要一步一步走
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next
        // 对于 fast 第二步,需要先判断,
        // 如果 fast 后面还可以再走一步,才往后走
        if (fast.next) {
            fast = fast.next
        }
    }
    // 链表翻转
    let newHead = null, pre = null;
    let cur = slow.next;
    // 前半部分和后半部分断开联系
    slow.next = null;
    while (cur) {
        pre = cur;
        cur = cur.next
        pre.next = newHead;
        newHead = pre;
    }
    // 现在 newHead 就是后半段翻转后的样子,然后接下来跟前半部分 依次 插入新链表
    let resultHead = new ListNode(0), now = resultHead, flag = true;
    slow = head, fast = newHead;
    while (slow || fast) {
        // 通过 flag 控制现在插入 前半部分 还是 后半部分
        if (flag) {
            now.next = slow;
            slow = slow.next;
        } else {
            now.next = fast;
            fast = fast.next;
        }
        now = now.next;
        flag = !flag;
    }
    return resultHead.next;
}

来源:力扣(LeetCode)

链接:leetcode.cn/problems/re…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。