重排链表

103 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

给定一个单链表 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

思路

单链表查找只能顺着链表方向,读完题目之后,我们发现偶数结点的n、n-1这部分是逆序的,为了挨个遍历这部分并插入,我们需要找到这些结点,并将其翻转。

从哪里开始翻转呢,奇数和偶数各占一半,因此我们只需要找到中间结点即可。当然,总数如果是奇数,找到是最中间的结点,为偶数,找到后一半的第一个结点。怎么找?用双指针法,前一个指针每次走一步,后一个指针每次走两步,后一个指针走到最后,第一个指针刚好找到中间结点。

随后,我们将前一半顺序的结点和后一半逆序的结点合并成一个链表即可。

代码

    if (head == null) {
        return;
    }
    //存到 list 中去
    List<ListNode> list = new ArrayList<>();
    while (head != null) {
        list.add(head);
        head = head.next;
    }
    //头尾指针依次取元素
    int i = 0, j = list.size() - 1;
    while (i < j) {
        list.get(i).next = list.get(j);
        i++;
        //偶数个节点的情况,会提前相遇
        if (i == j) {
            break;
        }
        list.get(j).next = list.get(i);
        j--;
    }
    list.get(i).next = null;
}


总结

本题要重排链表,观察案列可发现规律,只需要借助快慢指针找到链表中间节点,把后半段链表反转后,合并前半段链表,即可得出答案。