目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
题目给我们一个链表,让我们两两交换相邻节点的值,并且不能通过修改节点内部的值来达到这一目的,如果可以直接修改的话那就很简单了,不可以就会稍微复杂一点点。
不过这题还是比较考验操作链表的基本功了。一般要操作链表的题目,我们都需要定义一个节点指向初始链表的头结点,我们一般叫它哨兵,当然了在栈中也有哨兵这个概念。
在本题中哨兵可以保护我们不做空指针操作。我们之前做过反转链表,那时候我们需要用到三个节点来操作,而一个前驱节点(pre)一开始是空指针,只有在后面才会更新。如果链表很短的话,那么前驱节点(pre)就得不到更新,如果我们操作它,那么就会操作到空指针进而引发异常。
而有了哨兵,因为哨兵的后驱就是初始链表的头结点,所以前驱节点(pre)可以更新为哨兵,这样就操作不到空指针了。
那介绍完了哨兵的作用,我们再来看看这道题应该怎么做到两两交换。
涉及到节点交换,我们都是需要三个节点来帮助我们的进行操作的,前驱节点(pre),当前节点(cur),后驱节点(next)。
因为是两两交换,换之后第一个节点在后面的位置,第二个节点在前面的位置,我们操作之前当前节点指向的是第一个节点,前驱节点指向的是第一个节点的上一个节点。
需要我们在循环体里更新的是后驱节点,更新为当前节点的下一个节点。并且循环的条件是当前节点以及当前节点的下一个节点都不是空指针,不满足条件则表名剩下的节点不到两个,不足以让我们进行操作。
然后我们将当前指针的后驱改为后驱指针(next)的后驱,再将后驱指针(next)的后驱改为当前节点,这样我们就将两个节点的先后顺序交换了,不过仅限于这两个节点和两个节点后面的相邻节点,因为我们还需要修改这两个节点之前的相邻节点的指向。
所以还需要将前驱节点(pre)的后驱改为后驱节点(next),这样就算交换完毕了。
为了进行下一次的循环,我们需要移动当前节点(cur)和前驱节点(pre)。将前驱节点移动到当前节点的位置,再将当前节点移动到它的后驱。
这样一直循环直到剩余链表不足两个节点即退出循环。再将哨兵的后驱返回出去就可以啦。
代码:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* res=new ListNode(0,head);
ListNode* pre=res;
while(head!=nullptr && head->next!=nullptr){
ListNode* next=head->next;
head->next=next->next;
next->next=head;
pre->next=next;
pre=head;
head=head->next;
}
return res->next;
}
};