hot 100 第三十题 30. 两两交换链表中的节点

题目

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

复制代码
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

复制代码
输入:head = []
输出:[]

示例 3:

复制代码
输入:head = [1]
输出:[1]

核心思路

迭代法:每次处理两个节点,改变它们的next指针实现交换。

复制代码
原链表: 1 → 2 → 3 → 4

交换1和2:
2 → 1 → 3 → 4

交换3和4:
2 → 1 → 4 → 3

结果: 2 → 1 → 4 → 3

题解

复制代码
class Solution {
    public ListNode swapPairs(ListNode head) {
        // 使用哑节点简化处理
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode prev = dummy;
        
        // 至少需要两个节点才能交换
        while (prev.next != null && prev.next.next != null) {
            // 定义要交换的两个节点
            ListNode first = prev.next;
            ListNode second = prev.next.next;
            
            // 交换节点(三步)
            first.next = second.next;   // 1指向3
            second.next = first;        // 2指向1
            prev.next = second;         // prev指向2
            
            // 移动prev到下一对的前一个节点
            prev = first;
        }
        
        return dummy.next;
    }
}
```

### 详细演示
```
原链表: 1 → 2 → 3 → 4

步骤1: 创建哑节点
------------------
dummy → 1 → 2 → 3 → 4
prev↑

步骤2: 第一次交换(1和2)
------------------
定义节点:
first = 1
second = 2

交换前:
dummy → 1 → 2 → 3 → 4
prev↑  ↑   ↑
     first second

执行交换三步:

① first.next = second.next
   1 → 3

dummy → 1 → 2 → 3 → 4
        ↓       ↑
        └───────┘

② second.next = first
   2 → 1

dummy → 1 ← 2   3 → 4
        ↓   ↑
        └───┘

③ prev.next = second
   dummy → 2

dummy → 2 → 1 → 3 → 4
        ↑   ↓   ↑
        └───┴───┘

交换完成:
dummy → 2 → 1 → 3 → 4

移动prev:
prev = first (现在first是节点1)

dummy → 2 → 1 → 3 → 4
            prev↑

步骤3: 第二次交换(3和4)
------------------
定义节点:
first = 3
second = 4

交换前:
dummy → 2 → 1 → 3 → 4
            prev↑ ↑   ↑
                 first second

执行交换:
① first.next = second.next
   3 → null

② second.next = first
   4 → 3

③ prev.next = second
   1 → 4

结果:
dummy → 2 → 1 → 4 → 3 → null

移动prev:
prev = first (节点3)

步骤4: 检查循环条件
------------------
prev.next = 3
prev.next.next = null

条件不满足,循环结束

返回 dummy.next
最终: 2 → 1 → 4 → 3
```

## 交换的三步详解

这是最关键的部分,顺序不能错:
```
交换前:
prev → first → second → next
  ↑      ↑       ↑       ↑
dummy    1       2       3

目标:
prev → second → first → next
  ↑      ↑       ↑       ↑
dummy    2       1       3

三步:
------------------
步骤1: first.next = second.next
让1指向3(跳过2)

prev → first   second → next
        ↓   ╲    ↑       ↑
        └────╲───┘       │
              ╲__________│

步骤2: second.next = first
让2指向1

prev → first ← second → next
        ↓              ↗
        └──────────────┘

步骤3: prev.next = second
让prev指向2

prev ──→ second → first → next
           ↑       ↑       ↑
           2       1       3

完成!
```

## 图解交换过程
```
原始状态:
dummy → 1 → 2 → 3 → 4
        ↑   ↑
      first second

目标状态:
dummy → 2 → 1 → 3 → 4
        ↑   ↑
     second first

改变指针方向:
1. 1.next = 3     (1跳过2)
2. 2.next = 1     (2指回1)
3. dummy.next = 2 (dummy指向2)

本质

两两交换链表节点体现了:

  1. 指针作 --- 改变next指针实现节点重排
  2. 固定的交换步骤 --- 三步法完成交换
  3. 哑节点技巧 --- 统一处理头节点

关键是理解交换的三步顺序

  1. first.next = second.next(保存后续)
  2. second.next = first(交换)
  3. 上一页下一页 = second(连接)
相关推荐
旖旎夜光16 小时前
LCR 173:在点名(二分查找) —— 题解
数据结构·c++·算法·leetcode·二分查找
重生之后端学习16 小时前
438. 找到字符串中所有字母异位词[中等]✅
开发语言·数据结构·算法·leetcode·职场和发展
渡之16 小时前
ArduPilot LowPassFilter 深度解析
算法·无人机
ting94520001 天前
Humalike X Hermes 深度技术剖析:单指令注入群聊社交智能的底层架构、算法与跨 IM 平台实现
人工智能·算法·架构
吴声子夜歌1 天前
Java面试——算法
java·算法·面试
evans在进步1 天前
LeetCode 64:最小路径和——Java 原地动态规划详解
java·leetcode·动态规划
h_a_o777oah1 天前
【图论】Tarjan 缩点:解决有向图中环的问题
c++·算法·图论·acm·强连通分量·缩点·tarjan
Tisfy1 天前
LeetCode 1386.安排电影院座位:哈希表+位运算
算法·leetcode·散列表·题解·哈希表
Nil2081 天前
leetcode 199二叉树的右视图
算法·leetcode·深度优先
M78佐菲1 天前
c语言学习笔记:排序与查找方法整理
linux·c语言·笔记·学习·算法