题目
- 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
// An highlighted block
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100
解题思路
一、首先将问题简单化,如何将两个节点交换位置?
- 1.如下图创建1个head链表[1,2],其中p和q分别指向需要交换的两个节点。
- 2.翻转两节点步骤:
步骤1:将头指针指向q节点处,以便翻转过来时,头指针(head)依然指向第一个节点。
步骤2:将第一个节点指向第二个节点的下一个节点。
步骤3:将第二个节点指向第一个节点。整理一下如下图,即翻转成功。
小结: 以上步骤代码如下:
head = q;
p.next = q.next;
q.next = p;
二、回归到题目问题上来,需要两两翻转,无非就是移动p和q指针,然后根据上面的节点交换规则,进行翻转。那么如何移动p和q指针,保证位置正确呢?(创建一个哑节点,时刻来初始化一下p和q的位置)
下面按照题目示例1所示进行解释:
步骤1:创建哑节点or,并指向head节点。创建p和q指针和first指针,初始化p和q的位置,同时都指向哑节点处,first指针指向链表的第二个节点,作为输出的首节点。
代码:
//输出用的头节点,即指向第二节点
ListNode first = head.next;
//创建哑节点,并指向链表的首节点
ListNode or = new ListNode();
or.next = head;
//创建p,q指针,并指向哑节点初始位置
ListNode p = or;
ListNode q = or;
步骤2:上面已经初始化了,从这开始后面翻转的循环过程。
1)将p指向or节点的下一个节点,即p指向了1节点,再将q指向p的下一个节点,即指向了2节点。
代码:
if(or.next!=null){//初始化p节点位置,保证p指向的不为空
p = or.next;
}else{
break;//跳出循环,不用翻转
}
if(p.next!=null){//初始化q节点位置,保证q指向的不为空
q = p.next;
}else{
break;//跳出循环,不用翻转
}
2)根据上面两节点交换位置,规则进行交换。
代码:
p.next = q.next;
q.next = p;
3)需要将哑节点置于链表首部前面。
代码:
or.next = q;
4)将or指针指向p指向的位置,同时也将q指向p的位置,即下一次翻转的初始位置。
代码:
or = p;
q = p;
5)重复1)步骤,即:
6)重复2)步骤,即:
7)重复3)步骤,这里是将节点1指向节点4。
8)重复4)步骤,再循环重复1)步骤,直接跳出循环,返回first链表,即本题的解。
JAVA代码实现
//leetcode submit region begin(Prohibit modification and deletion)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
//处理空节点
if(head ==null) return head;
//处理只有一个节点
if(head.next == null) return head;
//输出用的头节点,即指向第二节点
ListNode first = head.next;
//创建哑节点,并指向链表的首节点
ListNode or = new ListNode();
or.next = head;
//创建p,q指针,并指向哑节点初始位置
ListNode p = or;
ListNode q = or;
while(p!=null && q!=null){//保证p和q中指向的节点不为空,才可以进行翻转
if(or.next!=null){//初始化p节点位置,保证p指向的不为空
p = or.next;
}else{
break;
}
if(p.next!=null){//初始化q节点位置,保证q指向的不为空
q = p.next;
}else{
break;
}
//翻转两节点
p.next = q.next;
q.next = p;
//关联交换位置后的首节点。
or.next = q;
//转移到下一个位置的初始。
or = p;
q = p;
}
return first;
}
}
//leetcode submit region end(Prohibit modification and deletion)