思路&代码
个人思路是,每次拆下来两个节点,进行重新拼接,但是拆节点之前,要先让后续的链表还有指针指向(否则后续造成链表丢失),如下代码中指针 m 表示每次拆节点之前,剩余链表头指指针。另外,重新拼接等介于重新构建链表,采用的尾查法,所以定义每次插入新节点前的前驱指针 t,指针 h 表示新链表的头指针(当然题目中也可以是使用head).核心处理点在,第一次拆节点组装,跟每 次要新拆的两节点的跳转条件之,以及退出循环之后的条件判断.
代码(有注释说明)
package main
import "fmt"
type ListNode struct {
Val int
Next *ListNode
}
func swapPairs(head *ListNode) *ListNode {
// 临界条件,链表为空或者只有一个节点
if head == nil {
return nil
}
if head.Next == nil {
return head
}
/*
个人思路是,每次拆下来两个节点,进行重新拼接,但是拆节点之前,要先让后续的链表还有指针指向(否则后续造成链表丢失),
如下代码中指针 m 表示每次拆节点之前,剩余链表头指指针。另外,重新拼接等介于重新构建链表,采用的尾查法,所以重新定义每次
插入新节点前的前驱指针 t,指针 h 表示新链表的头指针(当然题目中也可以是使用head).核心处理点在,第一次拆节点组装,跟每
次要新拆的两节点的跳转条件之,以及退出循环之后的条件判断.
*/
var p, q, t, m, h *ListNode
p = head
q = head.Next
for p != nil && q != nil {
m = q.Next // 拆节点前,让m指针指向剩余的链表节点
if h == nil { // 第一次拆,将q作为新链表头节点,
h = q
t = h
t.Next = p // 新链表的第二个节点(原来链表的头节点)
p.Next = nil
t = t.Next // 新链表的要插入节点的前驱节点
} else {
// 后续的链表构建处理
t.Next = q
q.Next = p
p.Next = nil
t = p
}
// 后续要拆的两个节点的指针跳转条件
p = m
if p != nil {
q = m.Next
}
}
if p == nil {
return h
}
if q == nil {
t.Next = p
}
return h
}
func (l *ListNode) Display() {
for h := l; h != nil; h = h.Next {
fmt.Println(h.Val)
}
fmt.Println("------")
}
func main() {
var t *ListNode
root := &ListNode{
Val: 1, Next: nil,
}
t = root
n := &ListNode{
Val: 2, Next: nil,
}
t.Next = n
t = t.Next
n = &ListNode{
Val: 3, Next: nil,
}
t.Next = n
t = t.Next
n = &ListNode{
Val: 4, Next: nil,
}
t.Next = n
t = t.Next
root.Display()
swapPairs(root).Display()
}
输出结果:
1
2
3
4
------
2
1
4
3
------