前端算法小白攻略32-leetcode(重排链表)

425 阅读2分钟

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

前言

今天我们要复习的重点是利用快慢指针、反转链表以及插入节点三个知识点来做一道链表重排的题目。

题目描述

给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/re… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

从题目中我们可以初步看出来重排列表是将链表后面部分节点反转过来再逐个连接到前半部分的链表上去的,下面我们结合图例来进一步探究题意:
偶数个节点

  输入: 1->2->3->4  
  输出: 1->4->2->3

1643814771(1).jpg
奇数个节点

  输入: 1->2->3->4->5  
  输出: 1->5->2->4->3

image.png
这里我们来说明一下上面两个流程图中重排链表的过程:

  1. 第一步我们要做的是,先把原链表分成左右两个链表,偶数节点对半分,奇数节点左链表比右链表多一个,这里我们可以用快慢指针的方式来实现,快指针以两倍速度走完时如果是偶数个节点,慢指针走到链表的一半位置,如果是奇数个节点,慢指针刚好走到链表中间位置,划分左右链表;
  2. 将右链表反转
  3. 移动链表指针,将右链表的节点依次逐个连接到左链表节点的后面

开始解题

var reorderList = function(head) {
    let hair = new ListNode(-1,head);  // 设置虚头作为左右快慢指针的起始节点
    let left = hair, right = hair;
    while(right && right.next) {
        left = left.next;             // 左指针位慢指针一次走一步
        right = right.next.next;      // 右指针位慢指针一次走两步
    }
    right = left.next;                // 左指针指向的是做部分的尾节点,它的下一个节点刚好指向要分隔的右链表
    left.next = null;                 // 将左指针断开与右链表的指向
    left = head;                      // 左指针指向头结点,分隔出左链表

    // 反转链表
    let reversR = null;             
    while (right) { 
        let next = right.next; 
        right.next = reversR; 
        reversR = right;
        right = next; 
    }

    // 插入节点
    while(left && reversR) {
        let tempL = left.next;
        let tempR = reversR.next;
        left.next = reversR;
        reversR.next = tempL;
        reversR = tempR;
        left = tempL;
    }
    return head;
};