算法-反转链表

一、题目描述

(一) 题目

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

(二) 示例

示例 1:

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

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

示例 2:

输入:head = [1,2]

输出:[2,1]

示例 3:

输入:head = []

输出:[]

(三) 提示

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

二、代码实现

(一) 迭代

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;
    }
}

2. 复杂度分析

时间复杂度

O(n),其中 n 是链表的长度,需要遍历链表一次。

空间复杂度

O(1),定义的变量使用的常数大小空间。

(二) 递归

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. 复杂度分析

时间复杂度

O(n),其中 n 是链表的长度,每个节点都需要进行反转处理。

空间复杂度

O(n),其中 n 是链表的长度,递归深度占用的栈内存空间。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
反转链表中从位置 m 到 n 的部分,可以按以下步骤进行操作: 首先,找到第 m 个节点和第 n 个节点的位置。 然后,我们将从第 m 个节点到第 n 个节点的部分链表进行反转操作。 最后,将反转后的部分链表重新连接到原链表中。 下面是具体的算法实现: 1. 声明一个 dummy 节点,并将其 next 指针指向头节点。同时声明 pre 指针指向 dummy 节点。 2. 将 pre 指针移动到第 m - 1 个节点的位置。 3. 声明一个 cur 指针指向 pre 指针的下一个节点。 4. 声明一个 tail 指针指向 cur 指针的下一个节点。 5. 从 m 到 n 的位置进行反转操作,需要进行 n - m 次迭代。 1. 将 cur 指针的 next 指针指向 tail 指针。 2. 将 pre 指针的 next 指针指向 cur 指针。 3. 将 cur 指针移动到 tail 指针的位置。 4. 将 tail 指针指向 cur 指针的下一个节点。 6. 将反转后的部分链表重新连接到原链表中,即将第 m - 1 个节点的 next 指针指向第 n 个节点。 7. 返回 dummy 节点的 next 指针。 以下是具体的实现代码: ```python def reverseBetween(head, m, n): dummy = ListNode(0) dummy.next = head pre = dummy # 得到第 m - 1 个节点 for _ in range(m - 1): pre = pre.next cur = pre.next tail = cur.next # 反转从第 m 个节点到第 n 个节点的部分链表 for _ in range(n - m): cur.next = tail.next tail.next = pre.next pre.next = tail tail = cur.next return dummy.next ``` 该算法的时间复杂度为 O(n - m),其中 n 是链表的长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值