携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情
题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3] 示例 2:
输入:head = [] 输出:[] 示例 3:
输入:head = [1] 输出:[1]
提示:
- 链表中节点的数目在范围 [0, 100] 内
- 0 <= Node.val <= 100
题目元素
- 给定一个链表,交换相邻链表节点,返回新的链表
解题思路
交换链表中的节点元素实际上考察的还是三个要点。哑元节点、虚拟节点和链表移动。
哑元节点已经在前面的题解中有过描述,它的主要目的就是将所有节点做统一处理,可以把它看成分数通分,通过设置一个空的前置节点使首节点可以和其它节点统一处理,降低代码复杂度。
虚拟节点,一般将虚拟节点用来指向当前操作节点,随着链表移动一直指向最新的节点,可以方便地进行节点的操作;
链表移动,链表是通过移动next来进行移动的,所以实质上就是将每次将当前操作节点设置成上一次操作节点的next,就可以实现链表的移动。
代码基本结构为
// 设置哑元节点
// 设置虚拟节点
while(root!=null){
// 链表操作
// 链表移动
// 虚拟节点设置
}
- 先设置哑元节点dummyNode,它的next节点指向真实的链表。
- 设置虚拟节点初始值赋值为dummyNode,因为第一次遍历对象应该为链表的第一个元素;
- 循环root节点,交换虚拟节点next与其后面节点
- 将虚拟节点的值赋值为当前节点
代码实现
/**
* @param head
* @return
*/
public ListNode swapPairs(ListNode head) {
// 设定哑元节点
ListNode dummyNode = new ListNode();
dummyNode.next = head;
// 设置虚拟节点
ListNode tailNode = dummyNode;
while (tailNode.next != null && tailNode.next.next != null) {
// 注意这里移动的对象是tailNode,tailNode一直指向的是当前操作节点的头节点
// 停止条件是需要交换的两个元素都不为空,如果其中一个为空就没有交换的必要了
// 需要交换的头一个元素
ListNode node1 = tailNode.next;
// 需要交换的后一个元素
ListNode node2 = tailNode.next.next;
// 交换两个元素的位置
tailNode.next = node2;
// 这两个对象都是引用对象类型,所以这里修改的都是链表内节点的next对象
node1.next = node2.next;
node2.next = node1;
tailNode = node1;
}
return dummyNode.next;
}