解法一:迭代
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode cur = dummyHead;
while(head != null && head.next != null){
ListNode next = head.next;
cur.next = next;
head.next = next.next;
next.next = head;
cur = head;
head = head.next;
}
return dummyHead.next;
}
}
对于本题,我引入了一个dummyHead,让dummyHead作为head的前驱节点,即:dummyHead.next = head
这样做的原因是:如果从head开始迭代,我们不需要考虑head节点的前驱;但是迭代到链表的中间部分,我们就需要考虑当前遍历的节点和前驱的关系。引入dummyHead 就可以让问题的分析整齐划一。
对于while循环部分,可以参考我的示例图进行理解:
原始链表的状态:
经过如下代码变换后:
cur.next = next;
head.next = next.next;
next.next = head;
链表状态如下:
然后再将cur指向head,head指向head.next即可:
cur = head;
head = head.next;
对于链表的问题,只要涉及到迭代,一定要在纸上写写画画,千万不要像我的某个朋友一样全凭大脑想象,这样的话是无法想到答案的。
执行结果如下:
解法二:递归
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode second = head.next;
ListNode third = head.next.next;
second.next = head;
head.next = swapPairs(third);
return second;
}
}
代码执行情况:
递归的思路实际上是以每两个节点作为一个划分单元,首先让second节点的next指向head,这一步是让单元内的节点发生swap;然后让head.next指向下一个单元返回的头结点,即:head.next = swapPairs(third)
相比于迭代方法,递归的写法更容易理解,也更巧妙一些。迭代和递归的时间复杂度均为O(n),虽然递归额外调用了栈,但是我更推荐递归的写法。
网友评论