携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]内 0 <= Node.val <= 100
解题思路
迭代法
相信浅看一眼题目不少人和我一样第一反应是直接将两两的val属性进行互换。然而这道题明确说明只能交换节点,那就只能踏踏实实的绕了。
正常思路:
但是这么绕的话,会丢失前一个节点的信息,在第二次调换的时候前一个节点和后面的节点就关联不起来了。
为了方便节点的交换,做了一个前置节点,初始时,前置节点的next指针指向head。
node1表示前置节点的下一个节点,node2表示再下一个节点。
我们重新审视一遍这张图,如果我们想两两交换,那么:
- 保存节点2的next指向的节点。
- 将节点0的next指向节点2。
- 将节点2的next指向节点1。
- 重置起始节点为两两交换后的第二个节点。
一直重复这个操作,最终就能将整个链表进行两两交换了。
/** * Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*
//**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
if(!head || !head.next) return head;
let pre = new ListNode(0, head);
let h = pre;
while(h && h.next && h.next.next) {
let node1 = h.next; // 待交换节点1
let node2 = h.next.next; // 待交换节点2
const t = node2.next; // 保存节点2的下一个节点,防止丢失指向
h.next = node2;
node2.next = node1;
node1.next = t;
h = node1;
}
return pre.next;
};
递归
我们想象一下,如果通过递归的形式,那么当递归到最后两个节点时,逻辑应该是怎么样的?
节点3的next指向节点4的next,节点4的next指向节点3,最后返回两两交换之后的起始节点,也就是节点4。此时4->3->null,返回4。
var swapPairs = function(head) {
if(!head || !head.next) return head;
const next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
};