143. 重排链表

914 阅读2分钟

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

题目描述

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

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

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

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

image.png

思路分析

最简单的思路是不断的删除节点,并将其挂到另一个链表上

pre -> next = node -> next;、
node -> next =secondNode;
secondNode = node;

最后再将两个链表合并。

这种写法的坏处是显而易见的,一个是需要遍历三次(因为找到一半的位置需要一次遍历),一个是需要额外的内存空间.

对于如何找到一半的位置,我们可以使用快慢指针进行计算。

对于额外的内存空间,我们先对后半部分链表进行一次翻转,再进行合并

具体实现

对于翻转链表的代码

ListNode* reverseList(ListNode* head) {
    ListNode* tmp = head;
    ListNode* node = nullptr;
    while(tmp != nullptr) {
        ListNode* ptr = tmp->next;
        tmp->next = node;
        node = tmp;
        tmp = ptr;
    }
    return node;

}

总结

如果不考虑时间空间复杂度,这道题其实也会有其他的思路,这道题的一个难点在于找到每个插入节点的位置,这里我们其实可以通过一次遍历将链表各节点都记录在某个数组里面,然后根据数组的索引值,对链表进行插入,这样的话相当于不需要再去根据快慢指针和翻转链表去计算位置。

另外对于翻转链表,也有一个简单的办法,可以将其存入栈中,利用栈的后进先出来实现对链表的翻转。

做算法题的时候,固然有一个解法就可以了,但了解更多的解法并不是一件坏事