每日算法一练:剑指offer——链表篇(2)

1.训练计划III

        给定一个头节点为 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 指针反向。具体来说,对于每个节点,我们需要将它的 next 指针指向它的前一个节点,而不是它的下一个节点。

  2. 我们可以用两种方式来实现:

    • 迭代(双指针法):通过遍历链表并逐步修改 next 指针来实现反转。
    • 递归:通过递归的方式来遍历链表,在递归回溯时修改 next 指针。

算法流程

1. 迭代(双指针法)

  • 设置两个指针:pre(前驱节点)和 cur(当前节点)。
  • 遍历链表,对于每个节点:
    1. 暂存当前节点的下一个节点 tmp
    2. 将当前节点的 next 指向前驱节点 pre
    3. 移动前驱节点指针和当前节点指针,继续遍历链表。
  • 最后,pre 会指向反转后的链表头节点。

2. 递归法

  • 递归的终止条件是当前节点 curnull
  • 递归遍历链表,直到链表的最后一个节点。
  • 在回溯过程中,修改当前节点的 next 指向前驱节点。
  • 最终返回的是反转后的链表头节点。

复杂度分析

1. 迭代法

  • 时间复杂度O(N),其中 N 是链表的长度。需要遍历链表一次。
  • 空间复杂度O(1),只用了常数空间来存储 curpre 两个指针。

2. 递归法

  • 时间复杂度O(N),同样需要遍历链表一次。
  • 空间复杂度O(N),递归调用栈的最大深度为链表的长度。

代码示例

1. 迭代法

class Solution {
    public ListNode trainningPlan(ListNode head) {
        ListNode cur = head, pre = null;
        while (cur != null) {
            ListNode tmp = cur.next; // 暂存后继节点
            cur.next = pre;          // 修改 next 引用指向
            pre = cur;               // pre 暂存 cur
            cur = tmp;               // cur 访问下一节点
        }
        return pre; // 返回反转后的链表头节点
    }
}

2. 递归法

class Solution {
    public ListNode trainningPlan(ListNode head) {
        return recur(head, null);    // 调用递归并返回
    }

    private ListNode recur(ListNode cur, ListNode pre) {
        if (cur == null) return pre; // 终止条件
        ListNode res = recur(cur.next, cur);  // 递归后继节点
        cur.next = pre;              // 修改节点引用指向
        return res;                  // 返回反转链表的头节点
    }
}

        在这里,给出一个仿造双指针法写的迭代代码供参考

class Solution {
    /**
     * 翻转单链表
     * @param head 链表的头节点
     * @return 翻转后的链表头节点
     */
    public ListNode trainningPlan(ListNode head) {
        // 调用辅助递归方法,初始时前置节点为 null
        return recur(head, null);
    }

    /**
     * 递归方法实现链表翻转
     * @param cur 当前处理的节点
     * @param pre 当前节点的前一个节点(翻转后将成为当前节点的 next)
     * @return 翻转后的链表头节点
     */
    ListNode recur(ListNode cur, ListNode pre) {
        // 基础条件:当前节点为空时,返回 pre 作为新的头节点
        if (cur == null)
            return pre;
        
        // 暂存当前节点的下一个节点
        ListNode tmp = cur.next;

        // 将当前节点的 next 指向前一个节点,实现局部翻转
        cur.next = pre;

        // 递归处理下一个节点,并返回最终的头节点
        retu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值