本文已参与「新人创作礼」活动,一起开启掘金创作之路
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
package com.programmercarl.linkedlist;
import com.programmercarl.linkedlist.domain.ListNode;
import java.util.List;
/**
* @ClassName SwapNodesInPairs
* @Descriotion TODO
* @Author nitaotao
* @Date 2022/5/10 11:16
* @Version 1.0
**/
public class SwapNodesInPairs {
public static void main(String[] args) {
ListNode node8 = ListNode.builder().val(8).next(null).build();
ListNode node7 = ListNode.builder().val(7).next(node8).build();
ListNode node6 = ListNode.builder().val(6).next(node7).build();
ListNode node5 = ListNode.builder().val(5).next(node6).build();
ListNode node4 = ListNode.builder().val(4).next(node5).build();
ListNode node3 = ListNode.builder().val(3).next(node4).build();
ListNode node2 = ListNode.builder().val(2).next(node3).build();
ListNode node1 = ListNode.builder().val(1).next(node2).build();
System.out.println(swapPairs(node1));
}
/**
* 虚拟头结点
* 一共需要四个指针
* 当前结点前一个结点 当前结点 当前结点后一个结点 当前结点后第二个结点
*
* @param head
* @return
*/
public static ListNode swapPairs(ListNode head) {
//判断是否是空头结点
if (head == null) {
return null;
}
//当前结点
ListNode curNode = head;
//设置虚拟头结点
ListNode preHead = new ListNode(0, head);
//当前结点的前一个结点的位置,初始值代表虚拟头结点
ListNode preCurNode = preHead;
while (curNode != null) {
if (curNode.next == null) {
//如果当前结点是最后一个结点
return preHead.next;
}
//当前结点还有下一个结点
ListNode nextNode = curNode.next;
//当前结点的下下个结点,这个可能为null
ListNode thirdNode = nextNode.next;
//当前结点的前一个结点位置后移
preCurNode.next = nextNode;
//2->1
nextNode.next = curNode;
//1->3
curNode.next = thirdNode;
//当前结点的前一个结点位置后移
preCurNode = curNode;
//当前结点后移
curNode = curNode.next;
}
return preHead.next;
}
}
感觉这题还是蛮难的,至少对我来说。 总体思路,抽象出来四个指针 preCurNode 当前结点的前一个结点 curNode 当前结点 nextNode 当前结点未交换时的下一个结点 thirdNode 当前结点未交换时的下下个结点 做了得有10小时。看题解都看好久,都不容易。 有一点要注意的就是preCurNode,也是头疼我最久,看的最困难的地方 这个结点代表当前结点的前一个结点的位置,这样单看谁都懂什么意思,具体模拟时就不容易理解是干嘛的了。 第一次,初始化preCurNode值时,给的位置是虚拟头结点的位置,因为当前结点为第一个结点,前一个结点不存在。在第一次循环中,它的位置变化了两次,第一次变化 preCurNode.next = nextNode;此时相当于preHead.next=nextNode,因为此时preCurNode代表虚拟头结点preHead。这也是为什么最后返回preHead.next的原因。此时preCurNode就是preHead。第二次后移,也就是 preCurNode = curNode,它就不再是代表虚拟头结点preHead了,是代表1号结点的位置,而之后 curNode = curNode.next,即当前结点后移一位到3,又因为1->3,则preCurNode再次代表了当前结点的前一个结点,相当于虚拟头结点->1,只不过这次是1->3,此时curNode为3.