题意
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
难度
中等
示例
输入:head = [1,2,3,4]
输出:[2,1,4,3]
分析 1
看到这道题,我们要先搞清楚什么是两两交换,比如 1->2->3->4,交换后就是 2->1->4->3。
第一个和第二个交换,第三个和第四个交换,以此类推。
我们可以用递归来解决这个问题,递归的终止条件是当前节点或者下一个节点为空,那么递归的返回值就是当前节点。
比如说 1 和 2 交换后, 2 的 next 指向 1,1 的 next 指向下一次交换后的结果。
我们来看题解的代码:
class Solution {public ListNode swapPairs(ListNode head) {// 递归终止条件:链表没有节点或只有一个节点if (head == null || head.next == null) {return head;}// 准备交换ListNode firstNode = head;ListNode secondNode = head.next;// 递归处理剩下的节点firstNode.next = swapPairs(secondNode.next);// 交换secondNode.next = firstNode;// 返回交换后新的头节点return secondNode;}
}
本地测试
/*** @ClAssName SwapPairs* @Description 两两交换链表中的节点,用递归和 while 循环轻松解决* @Author 欧妮甲是神仙* @Date 2024/6/24 19:{MINUTE}*/
public class SwapPairs {public static void main(String[] args) {SwapPairs swapPairs = new SwapPairs();ListNode head = swapPairs.new ListNode(1);head.next = swapPairs.new ListNode(2);head.next.next = swapPairs.new ListNode(3);head.next.next.next = swapPairs.new ListNode(4);ListNode result = swapPairs.swapPairs(head);while (result !=null){System.out.println(result.val + " ");result = result.next;}}class ListNode{int val; //数据ListNode next; //指针ListNode(){}; //空参构造ListNode(int val){ //数据对象this.val = val;}//完整的对象ListNode(int val , ListNode next){this.val=val;this.next = next;}}public ListNode swapPairs(ListNode head){//1、递归终止条件:链表没有节点或只有一个节点if (head == null || head.next ==null){return head;}//2、准备交换//第一个节点ListNode firstNode = head;//第二个节点ListNode secondeNode = firstNode.next;//3、递归·处理后续节点 重点 =后面的处理后续节点的,比如3和4的 =前面是连接后续的节点的firstNode.next = swapPairs(secondeNode.next);//4、交换secondeNode.next = firstNode;//5、返回交换完后新的头节点return secondeNode;}}
我们从链表的头节点 head 开始递归,每次处理一对节点,交换这对节点后,递归处理剩下的节点。
如果链表没有节点或者只有一个节点,没有交换的需要,直接返回 head。看下面这幅图就明白了。
来看题解效率:
分析 2
如果不想使用递归的话,我们也可以使用一个 while 循环来解决。
第一步,我们创建一个虚拟节点作为新链表的头节点,这可以简化边界条件的处理,虚拟节点的下一个节点指向 head。
第二步,我们开始 while 循环,条件是 head 和 head.next 都不为空。
第三步,我们使用两个临时变量来保存 head 和 head.next,然后交换这两个节点。
第四步,记得更新指针。
第五步,返回虚拟节点的下一个节点。
我们来看下面的代码:
class Solution {public ListNode swapPairs(ListNode head) {// 创建哑节点ListNode dummy = new ListNode(-1);dummy.next = head;ListNode prev = dummy;while (prev.next != null && prev.next.next != null) {ListNode curr = prev.next; // 当前节点ListNode next = curr.next; // 下一个节点// 交换 curr 和 nextcurr.next = next.next;next.next = curr;prev.next = next;// 移动指针prev = curr;}return dummy.next;}
}
简单解释下:
- 创建一个虚拟节点 dummy,dummy 的 next 指向 head。
- 创建一个指针 prev,指向 dummy。
- 当 prev 的 next 和 next 的 next 都不为空时,进行交换。
- 交换后,prev 指向 curr,curr 指向 next,next 指向 curr 的 next。
- 返回 dummy 的 next。
因为增加了很多临时变量,所以代码没有递归简洁。
public ListNode swapPairsTwo(ListNode head){//1、创建一个虚拟的节点作为新链表的头节点,简化边界条件的处理,其下一个节点指向headListNode dummy = new ListNode(-1);dummy.next = head;ListNode prev = dummy;//2、我们while循环 ,条件是head和head.next都不为空while (prev.next != null &&prev.next.next != null){//3、使用两个临时变量来保存head和head.next,然后交换这两个节点ListNode curr = prev.next; //当前节点ListNode next = prev.next.next; // 下一个节点//4、交换curr和nextcurr.next = next.next;next.next = curr;prev.next = next;//5、移动指针prev = curr;}//最后返回头节点return dummy.next;}
来看题解效率:
总结
其实有关链表的相关题目,最重要的切入角度,就是理清楚节点之间的关系,然后在纸上画一画,不要一个劲的只靠脑子不靠笔,往往思考了很久的问题,动动笔,就会豁然开朗,再用代码准确的描述出思路,这样子链表的问题便迎刃而解。
那这道题考察的还是链表的数据结构,以及递归和 while 循环的一些临时变量和边界条件。
力扣链接:. - 力扣(LeetCode)