【算法】笔记:LeetCode 206. 反转链表

39 篇文章 3 订阅
25 篇文章 1 订阅

前言

这道题可以拆成几个小点去理解,本篇博文快速记录一下。有迭代和递归两种解法。迭代的解法空间复杂度更优秀,递归的思想更巧妙。这里主要总结下迭代的解法。并简要理解下递归的解法。

思考问题:把分开的节点连在一起

  • 以下是分开的节点(假定以下四个节点都能以数组的形式按序访问)
    在这里插入图片描述
  • 一个指针遍历既可以连在一起
    在这里插入图片描述在这里插入图片描述
  • 最终的结果
    在这里插入图片描述

结合原题:使用[迭代]解决卡点

题目用链表组织原始节点,也就是四个节点只能使用向后遍历的方式按序访问。
在这里插入图片描述

  • cur指针可以从头遍历到尾,结合上文尝试用一个指针去完成需求,会遇到难题
    在这里插入图片描述

引入新指针

新指针的使命是:在原始链表中记住cur 的下一个节点,在指针断裂后,依旧能让cur继续遍历。

在这里插入图片描述

  • 根据官方题解,把指针的名字改一下(思想是统一的)
    在这里插入图片描述

边界条件

  • 开始
    在这里插入图片描述

  • 结尾
    在这里插入图片描述

代码
	public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            // 暂时忽略链表反转的逻辑
            cur = cur.next; // 这句后续要改造
        }
        return pre;
  	}

反转的逻辑

  • 结果:加入第一个节点(第一个要加入的是NULL),下一轮开始加入cur指向的节点
    在这里插入图片描述
代码(完整答案)
	public ListNode reverseList(ListNode head) {
		if (head == null) {
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            // 1. 记住cur的下一个节点, 避免指针断裂后找不到后续元素
            ListNode next = cur.next;
            // 2. cur 指针指向pre,同时断开原链表的方向
            cur.next = pre;
            // 3. pre 这一轮的使命完成了, 下一轮要处理的pre就是当前的cur所指向的元素
            pre = cur;
            // 4. 同理, 下一轮要处理的cur就是刚刚保留起来防止找不到的节点 next
            cur = next;
        }
        return pre;
  	}

结合原题:使用[递归]解决卡点

递归掌握的还是不够好,参考人家的题解,以后加以复习
参考leetCode的题解的图去观察回溯的过程

思考三个问题

  • 这个问题的子问题是什么。
  • 当前层要干什么事情。
  • 递归出口。

完整代码

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

问题的子问题

node1 -> node2 -> node3 -> node4 反转整个链表可以视为以下过程的组合:

  • 1 ~ 3 节点 与 4 节点 反转: node1 -> node2 -> node3 ->[node4]

  • 1 ~ 2 节点 与 3 节点 反转:node1 -> node2 -> [node3 <- node4]

  • 1 节点 与 2 节点的反转: node1 -> [node2 <- node3 <- node4]

完成后: [node1 <- node2 <- node3 <- node4]

	
    public ListNode reverseList(ListNode head) {
        // 这个模型, 就是让程序递归到最深处的节点(遇到最后一个节点node4,再回到node3), 此时 head 为 node3
        ListNode newHead = reverseList(head.next);
        // 从 node4 回溯到 node1, 以下代码就是当前层要处理的问题
        head.next.next = head;
        head.next = null;
        return newHead;
    }

当前层要干什么

		// head.next 就是 node4, head 就是node3
        head.next.next = head;
        head.next = null;

在这里插入图片描述

在这里插入图片描述

递归出口

		if (head == null || head.next == null) {
            return head;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值