[LeetCode] 24. 两两交换链表中的节点

传送门:[LeetCode] 24. 两两交换链表中的节点

题目描述

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

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

示例 :

给定 1->2->3->4, 你应该返回 2->1->4->3.

链表定义如下:

public class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

分析与代码

解法一:递归

  • 我们假设链表只有三个结点,交换前两个结点。交换后,头结点应连向原来的第三个结点,第二个结点连向第一个结点,交换完成,第二个结点就是新的头结点了。但我们要先记下第二个结点,不然头结点连向了第三个结点,第二个结点就丢失了。

    public ListNode swapPairs(ListNode head) {
        ListNode newHead = head.next;
        head.next = head.next.next;
        newHead.next = head;
        return newHead;
    }
    
  • 这样只是处理了一次,要递归处理,我们就先进入递归去处理最后面的结点,然后再一路返回。就是先把每次的第三个结点当作头结点进行处理。我们把head.next = head.next.next改成head.next = swapPairs(head.next.next)就可以了。

  • 这样我们的操作其实就已经完成了,接下来就是判断递归终止的条件,两个结点以上才能交换,所以终止条件应是头结点为空,或头结点的下一结点为空。

代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newHead = head.next;
        head.next = swapPairs(head.next.next);
        newHead.next = head;
        return newHead;
    }
}

解法二:迭代

  • 我们先定义一个哑结点 dumb,把它与头结点相连,并定义一个 pre 结点,pre 结点始终表示当前进行交换的第一个结点的上一个结点,起始时即 dumb。

    ListNode dumb = new ListNode(0), pre = dumb;
    dumb.next = head;
    
  • 每次遍历,我们用 first 表示这次循环要交换的两个结点的第一个,second 表示第二个。像递归那样,我们还先假设链表只有三个结点,我们先把 first 连向第三个结点,second 连向 first,此时已交换了两个结点。

    ListNode first = pre.next;
    ListNode second = pre.next.next;
    first.next = second.next;
    second.next = first;
    
  • 但此时前一个结点仍然连向 first,应连回 second,交换后的 second 才是前一个结点的下一个结点。pre 结点始终表示当前进行交换的第一个结点的上一个结点,此轮的两个结点已交换,准备下一轮,pre 应更新为第三个结点的上一个结点,即 first ,因为 first 和 second 已经完成了交换,此时 first 结点就是第二个结点。

    pre.next = second;
    pre = first;
    
  • 循环进行的条件应该是当前进行交换的两个结点均不为空,即pre.next != null && pre.next.next != null

  • 最后我们应该返回的是 dumb 的下一个结点 dumb.next。

代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dumb = new ListNode(0), pre = dumb;
        dumb.next = head;
        while (pre.next != null && pre.next.next != null) {
            ListNode first = pre.next;
            ListNode second = pre.next.next;
            first.next = second.next;
            second.next = first;
            pre.next = second;
            pre = first;
        }
        return dumb.next;
    }
}

小结

个人觉得递归法很好理解,反而是迭代法有点绕,不过画一下图也就清楚了。

我发现,递归结束的条件和迭代进行的条件又是刚好相反。



┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-24.html