重排链表

97 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情

一、题目

leetcode 重排链表

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

L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

 

示例 1:

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

示例 2:

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

提示:*

链表的长度范围为 [1, 5 * 104]
1 <= node.val <= 1000

二、题解

需要将链表节点进行交换,将原链表的第一个节点和倒数第一个节点连接,第二个节点和倒数第二个节点连接,以此类推。

方法一

可以根据题意直接取原链表的头尾节点互相连接就行。具体的用一个双端队列deque来实现,将原链表节点顺序加入队列中,再新建一个dumb节点,然后再将队列元素节点一一取出。首先从队头取出队列一个元素节点first,也就是原链表的第一个节点,然后再从队尾取出队列的一个元素节点last,也就是原链表的最后一个节点。然后将取出否first节点连接到dumb后,然后再将last节点连接到first节点后,最后将dumb移动到last,然后继续取出下一个队头队尾元素,最后取出的一个last可能为null,这个时候就是交换完成了,如果last也就是dumb不为空,需要将dumb断开,否则节点会循环。

方法二

同时可以发现重排后的链表其实就是原链表的后半部分翻转之后再与前部分链表一一合并的结果。所以可以分三步,第一步将原链表分为两个部分,一部分为链表前半节点,一部分为链表的后半节点;然后第二步对链表后半部分的节点进行翻转;最后一步将前面 两部操作的结果链表进行两两连接合并,最后就得到了重排后的链表。

三、代码

方法一 Java代码

class Solution {
    public void reorderList(ListNode head) {
        Deque<ListNode> deque = new LinkedList<>();
        while (head != null) {
            deque.add(head);
            head = head.next;
        }
        ListNode dumb = new ListNode();
        while (!deque.isEmpty()) {
            ListNode first = deque.pollFirst();
            ListNode last = deque.pollLast();
            dumb.next = first;
            first.next = last;
            dumb = last;
        }
        if (dumb != null) {
            dumb.next = null;
        }
    }
}

时间复杂度:O(n),需要一次遍历添加节点到队列中,然后再遍历取出队列元素节点。

空间复杂度:O(n),需要一个队列存储原链表的节点。