LeetCode Notes_#24_两两交换链表中的节点
LeetCode Notes_#24_两两交换链表中的节点
Contents
题目
解答
方法1:迭代+修改指针
一开始自己写,发现有两个难点不好解决:
- 最后无法得到修改后链表的头节点
- 第一组的两个节点没法连接到第二组的两个节点,举例来说就是1没法连接到4
问题在于:
- 头节点需要通过哑节点
dummyHead.next
来获取,没有哑节点的话,是没法处理这个问题的 - 每次迭代开始的位置应该是“上一组的两个节点的尾巴”,举例来说,第二轮迭代时,
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)
,递归栈空间