SwapNodesInPairs [source code]

public class SwapNodesInPairs {
static
/******************************************************************************/
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode (0), slow = head;
        if (slow == null || slow.next == null)
            return head;
        ListNode fast = slow.next, slow_prev = dummy;
        dummy.next = head;
        while (true) {
            ListNode next = fast.next;
            slow_prev.next = fast;
            slow.next = next;
            fast.next = slow;
            // advance
            slow_prev = slow;
            if ((slow = slow.next) == null)
                break;
            if ((fast = slow.next) == null)
                break;
        }
        return dummy.next;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        SwapNodesInPairs.Solution tester = new SwapNodesInPairs.Solution();
        int[][] inputs = {
            {1, 2}, {2, 1},
            {1,2,3,4}, {2,1,4,3},
        };
        for (int i = 0; i < inputs.length / 2; i++) {
            ListNode head = ListNode.buildListNode (inputs[2 * i]);
            String head_str = ListNode.serialize (head);
            String ans_str = ListNode.serialize (ListNode.buildListNode (inputs[2 * i + 1]));
            System.out.println (Printer.separator ());
            ListNode output = tester.swapPairs (head);
            String output_str = ListNode.serialize (output);
            System.out.printf ("%s -> %s, expected: %s\n", 
                head_str, Printer.wrapColor (output_str, output_str.equals (ans_str) ? "green" : "red"), ans_str
            );
        }
    }
}

感觉又是一个脑筋急转弯的题目, 看给的这些限制就知道了, 想想办法;

最后还是一个有惊无险的AC了, 速度是4ms (62%). 这种题目, 最最重要的一点, 始终就是要多画图多笔算, 这个强调很多遍了;

一个小的细节是, 这题最好是第一次swap完成之后再advance; 因为我一开始初始化的时候, 两个指针是先初始化到实际的node上面的; 当然, 另外一个思路是可以用两个dummy head, 把slow和fast都先摆在上面, 这样循环里面就可以先advance然后再swap, 不过没有什么特殊的意义这样做, 现在这么写也挺好的;

意识到需要保存prev这个应该不难了; 最后advance的逻辑实际上就是自己画个图就知道了; 盯着代码看估计看的很乱; 另外这题本身确实不算难, 尤其是advance和cache prev之间的处理关系并不复杂;

看discussion的时候意识到我这里这个只要保证第一个iteration是先swap再advance, 那么实际上是不需要dummy的; 不过养成一个好习惯没坏处好吧;

这一题其实还是一个快慢指针的技巧, 而且跟之前一个delete Nth from end很像, 维护的是两个固定间距的指针而不是倍速. 注意这里的另外一个限制, 不允许你修改任何node本身的val, 实际上, 这种通过改val来投机取巧的做法在LinkedList题目当中还真不算少见; 之前那个题目就看到Stefan用过一次;

没有dummy的版本:

class Solution {  
    public ListNode swapPairs(ListNode head) {  
        ListNode slow = head;  
        if (slow == null || slow.next == null)  
            return head;  
        ListNode fast = slow.next, slow_prev = null, res = fast;  
        while (true) {  
            ListNode next = fast.next;  
            if (slow_prev != null)  
                slow_prev.next = fast;  
            slow.next = next;  
            fast.next = slow;  
            // advance  
            slow_prev = slow;  
            if ((slow = slow.next) == null)  
                break;  
            if ((fast = slow.next) == null)  
                break;  
        }  
        return res;  
    }  
}

没有editorial;


首先, 如果你仔细读了题目, 就注意到这里的空间限制非常的扎眼, 而我们以前说过, 一个规避空间限制的旁门左道就是recursion; 但是这个其实也是有一定风险的, 具体还是看实际面试的时候面试官是否允许, 因为Stack严格来说也是一个space占用;

@whoji said in My accepted java code. used recursion.:

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

这种recursion算法实际上设计起来并不简单; 但是掌握方法还是可以做的; 这种LinkedList的recursion, 一般都是标准的peel head recursion, 所以一般你确定你一个iteration的head到底是多少, 就不难处理了; 这里很明显, 一个head应该是两个node的一个pair; 然后你assume你后面返回上来的是一个正确的head for the rest of the list, 那么你当前iteration做什么? 想好就行了;

这种算法的设计, 一开始的一个难点是往往忘记了你的recursion函数是有返回值的, 而且往往返回的就是一个node. 把这个记清楚, 其他的设计往往就不是特别难了;

@navari said in My accepted java code. used recursion.:

No. the recursive stack uses O(n) space

一个不依赖prev指针的做法:

@zhugejunwei said in My accepted java code. used recursion.:

Iteration version:

public class Solution {  
    public ListNode swapPairs(ListNode head) {  
        if (head == null || head.next == null) return head;  
        ListNode cur = head;  
        ListNode newHead = head.next;  
        while (cur != null && cur.next != null) {  
            ListNode tmp = cur;  
            cur = cur.next;  
            tmp.next = cur.next;  
            cur.next = tmp;  
            cur = tmp.next;  
            if (cur != null && cur.next != null) tmp.next = cur.next;  
        }  
        return newHead;  
    }  
}

刚开始没看懂, again,还是要画图; 首先, 他意识到一个问题, 我们反正是两个两个的操作, 所以实际上不需要维护两个指针, 直接一个指针就行了; 因为LinkedList的性质, 所以我们肯定维护slow比较方便(你在fast的时候, 你是无法通过fast来access slow的); 另外一个insight就是, 虽然我们走到下一个pair的时候, 无法access之前的pair了, 但是这不代表我们无法维护两个pair之间的关系: every iteration is the prev of next iteration. 所以你只要在当前的pair, 提前在下一个pair找到合理的衔接位置就行了; 总体来说这个算法还是有点思路的;

对于recursion的另外一个理智批评:

@EDGE1777 said in My accepted java code. used recursion.:

@lekzeey unless compiler is geared towards tail recursion, this will cause stack overflow if the list is large enough (due to the function calls).

@cdai said in My accepted java code. used recursion.:

Very nice! Never thought that recursion could help save dmy, pre and tmp. The comparison is much clear as the followings. Thanks for sharing!

    // pre->cur->suc->tmp ==> pre->suc->cur->tmp ==> pre->suc->cur(pre)->tmp  
    public ListNode swapPairs(ListNode head) {  
        ListNode dmy = new ListNode(0), pre = dmy;  
        dmy.next = head;  
        while (pre.next != null && pre.next.next != null) {  
            ListNode cur = pre.next, suc = cur.next, tmp = suc.next;  
            pre.next = suc;  
            suc.next = cur;  
            cur.next = tmp;  
            pre = cur;  
        }  
        return dmy.next;  
    }  

    // O(N) time and space due to recursion  
    public ListNode swapPairs(ListNode cur) {  
        if (cur == null || cur.next == null) return cur;  
        ListNode suc = cur.next;  
        cur.next = swapPairs(suc.next);  
        suc.next = cur;  
        return suc;  
    }

@tusizi said in My simple JAVA solution for share:

    public ListNode swapPairs(ListNode head) {  
        ListNode dummy = new ListNode(0);  
        dummy.next = head;  
        ListNode current = dummy;  
        while (current.next != null && current.next.next != null) {  
            ListNode first = current.next;  
            ListNode second = current.next.next;  
            first.next = second.next;  
            current.next = second;  
            current.next.next = first;  
            current = current.next.next;  
        }  
        return dummy.next;  
    }

LinkedList类的题目思路还是很多的;


跟我的做法非常像的一个版本:

@YuTingLiu said in My straight-forward Java solution without recursion or dummy nodes (0ms):

  • The idea is straightforward: use two pointers and swap
    • a.next = b.next, b.next = a.
    • Then continue the next pair, b = a.next.next, a=a.next
    • Remember to check null
    • Remember to track new head
    • Remember to link the new pair after the prior nodes.

Attached is the accepted code.

public class Solution {  
  public ListNode swapPairs(ListNode head) {  
    if(head==null || head.next==null) return head;  
    ListNode newHead = head.next, a=head,b=a.next,pre = null;  
    while(a!=null && b!=null){  
      a.next = b.next;  
      b.next = a;  
      if(pre!=null) pre.next = b;  
      if(a.next==null) break;  
      b = a.next.next;  
      pre = a;  
      a = a.next;  
    }  
    return newHead;  
  }  
}
  • AC, 0ms

区别无非在于我的方法比他的更加依赖break一点, 无所谓了, 过了就行了;


submission基本波动, recursion稍微快一点;


Problem Description

Given a linked list, swap every two adjacent nodes and return its head.

For example,
Given 1->2->3->4, you should return the list as 2->1->4->3.

Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.

Difficulty:Medium
Total Accepted:199.2K
Total Submissions:511.5K
Contributor:LeetCode
Companies
microsoftbloomberguber
Related Topics
linked list
Similar Questions
Reverse Nodes in k-Group

results matching ""

    No results matching ""