Skip to content

24.两两交换链表中的节点

一、问题描述

给定一个链表,两两交换链表中的节点,并返回交换后的链表。

示例:

plaintext
给定 1->2->3->4, 你应该返回 2->1->4->3.

二、方案一:迭代法

1、思路

使用迭代法来两两交换链表中的节点。

  • 定义虚拟头结点,这样会方便很多,要不然每次针对头结点特殊处理(没有前一个指针指向头结点的场景)
  • 通过下面三个步骤完成相邻节点的交换,然后指针向后移动2位,重复上面的过程

2、代码实现

go
func swapPairs(head *ListNode) *ListNode {
	var dummy *ListNode = &ListNode{Next: head}
	var cur *ListNode = dummy
	for cur.Next != nil && cur.Next.Next != nil {
		// 保存第一个节点
		tmp1 := cur.Next
		// 保存后置节点
		tmp2 := cur.Next.Next.Next

		/* 第2个节点和第1个节点交换 */

		// 步骤一:前置节点指向第2个节点
		cur.Next = cur.Next.Next
		// 步骤2:第2个节点指向第1个节点
		cur.Next.Next = tmp1
		// 步骤3:第1个节点指向后置节点
		tmp1.Next = tmp2

		cur = cur.Next.Next // cur移动两位,准备下一轮交换
	}

	return dummy.Next
}

3、复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。我们需要遍历整个链表一次。
  • 空间复杂度:O(1),不需要额外的空间。

三、方案二:递归法

1、思路

使用递归法来两两交换链表中的节点。递归法的基本思路是:

  • 设置当前节点的下一个节点的指针指向当前节点。
  • 递归地交换剩余的链表。
  • 将当前节点的指针指向新的头节点。

2、代码实现

go
func swapPairs(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }
    // 创建一个节点指针类型保存头结点下一个节点
    newHead := head.Next
    // 更改头结点,并将头结点的next指针指向这个更改过的list
    head.Next = swapPairs(newHead.Next)
    // 将新的头结点的next指针指向老的头节点
    newHead.Next = head
    return newHead
}

3、复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。我们需要遍历整个链表一次。
  • 空间复杂度:O(n),递归调用栈的空间。

四、总结

方案时间复杂度空间复杂度
迭代法O(n)O(1)
递归法O(n)O(n)

迭代法在空间复杂度上更优,而递归法在代码结构上更简洁。选择哪种方法取决于具体的使用场景和个人偏好。

木川工作室 (微信:mcmc2024)