手摸手提桶跑路——LeetCode24.两两交换链表中的节点

75 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

题目描述

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

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

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100]
  • 0 <= Node.val <= 100

解题思路

迭代法

相信浅看一眼题目不少人和我一样第一反应是直接将两两的val属性进行互换。然而这道题明确说明只能交换节点,那就只能踏踏实实的绕了。

正常思路:

但是这么绕的话,会丢失前一个节点的信息,在第二次调换的时候前一个节点和后面的节点就关联不起来了。

为了方便节点的交换,做了一个前置节点,初始时,前置节点的next指针指向head。

node1表示前置节点的下一个节点,node2表示再下一个节点。

我们重新审视一遍这张图,如果我们想两两交换,那么:

  1. 保存节点2的next指向的节点。
  2. 将节点0的next指向节点2。
  3. 将节点2的next指向节点1。
  4. 重置起始节点为两两交换后的第二个节点。

一直重复这个操作,最终就能将整个链表进行两两交换了。

/** * Definition for singly-linked list. 
* function ListNode(val, next) { 
*     this.val = (val===undefined ? 0 : val) 
*     this.next = (next===undefined ? null : next) 
* } 
*
//** 
* @param {ListNode} head 
* @return {ListNode} 
*/
var swapPairs = function(head) {
    if(!head || !head.next) return head;
    let pre = new ListNode(0, head);
    let h = pre;
    while(h && h.next && h.next.next) {
        let node1 = h.next; // 待交换节点1
        let node2 = h.next.next; // 待交换节点2
        const t = node2.next; // 保存节点2的下一个节点,防止丢失指向
        h.next = node2;
        node2.next = node1;
        node1.next = t;
        h = node1;
    }
    return pre.next;
};

递归

我们想象一下,如果通过递归的形式,那么当递归到最后两个节点时,逻辑应该是怎么样的?

节点3的next指向节点4的next,节点4的next指向节点3,最后返回两两交换之后的起始节点,也就是节点4。此时4->3->null,返回4。

var swapPairs = function(head) {
    if(!head || !head.next) return head;
    const next = head.next;
    head.next = swapPairs(next.next);
    next.next = head;
    return next;
};