zoukankan      html  css  js  c++  java
  • 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),递归栈空间

  • 相关阅读:
    使用Git遇到的问题及解决方案(初级)
    巧记前端易混淆的英文语法
    编程助手JavaScript学习库-DOM笔记
    编程助手JavaScript学习库-面向对象编程笔记
    JS原始类型:数值的运用技巧
    这题目有毒之干不过codewars的OJ系统(一)
    Javascript运算符进阶指南
    Qt:During startup program exited with code 0xc0000135
    QT 消息处理机制
    Windows环境 和 Linux环境下搭建Qt开发环境
  • 原文地址:https://www.cnblogs.com/Howfars/p/13925184.html
Copyright © 2011-2022 走看看