143. 重排链表

84 阅读1分钟

[143. 重排链表]

「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。

题目描述

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

提示:

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

思路

这还是一道属于双指针在链表上使用的题,如果是在线性表的话,直接从头从尾开始,交错合并为新的线性表即可。但是是在链表上,没有办法从头开始遍历,当然也可以将链表转化为线性表后处理。这里我们来看一下不用转怎么做。我们来看一下线性表的做法。头指针向后遍历。链表同样可以做到。尾指针向前遍历,相当于将链表的后半截翻转,在从中间开始向后遍历,最后再将俩指针指向的链表合并,这样就可以了。

代码实现

按以上思路,需要实现找中间节点,翻转链表,合并链表的操作,具体的做法在之前的文章已有说明,这里不在复述,细节见代码注释。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        if (head == nullptr) {
            return;
        }
        ListNode* mid = middleNode(head);
        ListNode* l1 = head;
        ListNode* l2 = mid->next;
        mid->next = nullptr;     //将原链表切断,方便下来翻转
        l2 = reverseList(l2);    //翻转
        mergeList(l1, l2);       //合并
    }

    ListNode* middleNode(ListNode* head) {         //快慢指针找中间节点
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast->next != nullptr && fast->next->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    ListNode* reverseList(ListNode* head) {        //翻转链表
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr != nullptr) {
            ListNode* nextTemp = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }

    void mergeList(ListNode* l1, ListNode* l2) {    //合并链表
        ListNode* l1_tmp;
        ListNode* l2_tmp;
        while (l1 != nullptr && l2 != nullptr) {
            l1_tmp = l1->next;
            l2_tmp = l2->next;

            l1->next = l2;
            l1 = l1_tmp;

            l2->next = l1;
            l2 = l2_tmp;
        }
    }
};

总结

在链表上使用双指针,综合使用了链表上的多种操作。