24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
链表天然具有递归属性,可以把后面的数字当做整体来看,有点类似高中的整体受力法。
其中我们应该关心的主要有三点:
- 返回值
- 调用单元做了什么
- 终止条件
在本题中:
- 返回值:交换完成的子链表
- 调用单元:设需要交换的两个点为 head 和 next,head 连接后面交换完成的子链表(递归核心),next 连接 head(翻转核心),完成交换
终止条件:head 为空指针或者 next 为空指针,也就是当前无节点或者只有一个节点,无法进行交换 ```go //递归法,通法,经典递归思路,时间复杂度On,空间复杂度On func swapPairs(head ListNode) ListNode { if head == nil || head.Next == nil {
return head //当后面的数字为空,或者为一个时,直接返回当前指针数
//终止条件:链表只剩一个节点或者没节点了,没得交换了。返回的是已经处理好的链表
}
//一共三个节点:head, temp, swapPairs(temp.next) //下面的任务便是交换这3个节点中的前两个节点 temp := head.Next //head表示头节点,temp表示第二个节点,暂存数字,链表都有:= head.Next = swapPairs(temp.Next) //递归核心,去掉swap函数,就不走了,只交换了前两个数 //head.Next = temp.Next // 交换后的新节点为head节点的下一跳,其实就是temp前,head后 temp.Next = head //翻转核心,temp下一跳指向本次前数 //根据第二步:返回给上一级的是当前已经完成交换后,即处理好了的链表部分
return temp //返回新头结点,后节点 }
```go
//简化代码:递归法,时间复杂度On,空间复杂度On
func swapPairs(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
cur := head
temp := cur.Next
cur.Next = swapPairs(temp.Next) //新的脚步cur.Next
temp.Next = cur //两两前进,记录原脚步
return temp //这样就可以理解返回temp,因为temp是前脚
}
思路
- 设置虚拟头结点 fack,因为真实头结点要换人,设置了 fack 后,fack.next 就能找到头结点。
- 开启 while 循环,一对结点的交换有三个指针要改变,见下图。
- 指针推进,准备交换下一对结点。
- 最后返回 fack.next 。
```go //简化代码,迭代法,时间复杂度On,空间复杂度O1,就是头插法 func swapPairs(head ListNode) ListNode { dummy := &ListNode{Next: head} prev := dummy
cur := head for cur != nil && cur.Next != nil {
temp := cur.Next cur.Next = temp.Next temp.Next = prev.Next prev.Next = temp prev = cur //cur是两个一动,手动赋值前进; cur = cur.Next //注意原来是cur->temp; 现在是temp->cur->新的
} return dummy.Next }
```