LeetCode Notes_#24_两两交换链表中的节点

LeetCode Notes_#24_两两交换链表中的节点

Contents

题目


解答

方法1:迭代+修改指针

一开始自己写,发现有两个难点不好解决:

  1. 最后无法得到修改后链表的头节点
  2. 第一组的两个节点没法连接到第二组的两个节点,举例来说就是1没法连接到4

问题在于:

  1. 头节点需要通过哑节点dummyHead.next来获取,没有哑节点的话,是没法处理这个问题的
  2. 每次迭代开始的位置应该是“上一组的两个节点的尾巴”,举例来说,第二轮迭代时,cur指针应该是1的位置,而不是3的位置。

具体来说,我们需要维护3个指针,第一个指针指向的是“上一组的两个节点的尾巴”,后两个指针则指向下一组节点的两个节点。这样就比较方便进行各种指针的修改。

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode cur = dummyHead;
        while(cur.next != null && cur.next.next != null){
            ListNode node1 = cur.next;
            ListNode node2 = cur.next.next;
            node1.next = node2.next;
            cur.next = node2;
            node2.next = node1;
            cur = cur.next.next;
        }        
        return dummyHead.next;
    }
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(1)

方法2:迭代+栈

我们还可以利用栈的性质,将原始链表节点入栈,然后将出栈的节点加入新的链表,以达到反转的目的。这样的方法直接避免了复杂的指针操作,代码看起来非常清晰,其实运行效率并不比方法1要低。

class Solution {
    public ListNode swapPairs(ListNode head) {
        //注意:这种方法并不是在原地进行修改,而是创建一条新链表,新链表的哑头节点是newListDummy
        ListNode newListDummy = new ListNode(0);
        Deque<ListNode> stack = new LinkedList<>();
        ListNode newListPtr = newListDummy;
        ListNode oldListPtr = head;
        while(oldListPtr != null && oldListPtr.next != null){
            //将原始链表上的节点入栈
            stack.addLast(oldListPtr);
            stack.addLast(oldListPtr.next);
            oldListPtr = oldListPtr.next.next;
            //将刚才加入的两个节点出栈,连接到新链表之后
            newListPtr.next = stack.removeLast();
            newListPtr.next.next = stack.removeLast();
            newListPtr = newListPtr.next.next;
        }
        //因为循环结束,证明oldListPtr和oldListPtr.next不会同时非null
        //只有两个可能,第一种是:oldListPtr非null,而ololdListPtr.next是null(对应于奇数个节点的情况)
        if(oldListPtr != null){
            newListPtr.next = oldListPtr;
        }
        //第二种是:oldListPtr和ololdListPtr.next都是null(对应于偶数个节点的情况)
        else{
            //如果没有这一句,会导致链表中出现环,无法通过
            newListPtr.next = null;
        }
        return newListDummy.next;
    }
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n),创建了一条新的链表

方法3:递归

看到一个很好的图解,转载自三道题套路解决递归问题 | lyl's blog


这个写法看起来有点难懂...感觉我自己是根本不会想到这种方法的。

class Solution {
    public ListNode swapPairs(ListNode head) {
        //递归终止条件:链表只剩一个节点,或者没有节点了,就没得交换了,返回已经处理好的链表
        if(head == null || head.next == null){
            return head;
        }
        //仅仅是暂存一下head.next,因为接下来head.next要改变了
        ListNode next = head.next;
        //递归调用,传入的参数是下下个节点,也就是说,从下一组开始翻转
        head.next = swapPairs(next.next);
        //这一句和上一句不能交换位置,因为交换过后next就先改变了
        next.next = head;
        return next;
    }
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n),递归栈空间

posted @ 2020-11-04 12:00  Howfar's  阅读(138)  评论(0编辑  收藏  举报