206. 反转链表

题目链接

一、题目描述

1. 题目

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

2. 示例

示例 1:

输入:head = [1,2,3,4,5]

输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]

输出:[2,1]

示例 3:

输入:head = []

输出:[]

3. 提示

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

二、代码实现

1. 迭代

1.1 解题思路

解决方案是通过维护双指针来进行遍历,通过将当前节点的 next 节点指向一个新的 pre 节点。指针如果改变,后续的值还需要使用时,需要用一个 temp 节点暂存后继节点的值。

图解如下:

代码实现如下:

class Solution {
public ListNode reverseList(ListNode head) {
// 初始化 cur 和 pre指针,以及 temp 作为暂存后继节点
ListNode cur = head;
ListNode pre = null;
ListNode temp = null;
while(cur != null){
temp = cur.next; //暂存后继节点
cur.next = pre; //改变节点指向
pre = cur; //pre 指针后移
cur = temp; //cur 指针后移
}
return pre;
}
}

1.2 复杂度分析

时间复杂度 O(n),其中 n 是链表的长度,需要遍历链表一次。
空间复杂度 O(1),定义的变量使用的常数大小空间。

2. 递归

2.1 解题思路

链表、树、图相关的算法首先想递归。递归相关的知识见我的另一篇文章迭代与递归

递归设计函数的步骤:

1. 找重复: 找到的相同的子问题。

我们想将链表的节点反转,也就是说要将每个节点的指向反转过来,所以这里的子问题就是,调整每个节点的指向。

2. 找变化: 聚焦于某一个子问题,查看变化的量,通常会作为参数,这时可定义函数体;

如图,针对最后两个节点,变化的量只有 cur 指针,代表着层层遍历的节点。这里的递归函数入参就是当前节点的后继节点。

定义函数体:

private ListNode recursion(ListNode cur){
//递归调用后继节点
recursion(cur.next);
}

3. 找出口: 也就是找终止条件,这里注意关注返回值。

找终止条件首先关注返回值,这里的返回值我们如何定义呢?因为这里的链表是单向的,也就是无法获取节点对应的前驱节点。

所以我们需要再递归的归中操作节点指向的反转,这样就可以得到返回值,必须是返回当前的节点,再上一层进行节点指向反转。

那什么时候才终止递归呢?当前节点为 null 时,则没必要再进行反转。还有一个情况时当前节点的后继节点为 null 时,由于我们递归函数的入参就是当前节点的后继节点,故也没必要再次递归,直接返回当前节点即可。

最终代码示例:

private ListNode recursion(ListNode cur){
if(cur == null || cur.next == null){
return cur;
}
//递归调用后继节点
ListNode result = recursion(cur.next);
//后继节点指向当前节点
cur.next.next = cur;
//切断当前节点的后继节点,防止链表产生环形
cur.next = null;
return result;
}

2.2 复杂度分析

时间复杂度 O(n),其中 n 是链表的长度,每个节点都需要进行反转处理。
空间复杂度 O(n),其中 n 是链表的长度,递归深度占用的栈内存空间。
posted @   fuxing.  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
一、题目描述1. 题目2. 示例3. 提示二、代码实现1. 迭代1.1 解题思路1.2 复杂度分析2. 递归2.1 解题思路2.2 复杂度分析
点击右上角即可分享
微信分享提示