看我如何用两只兔子解决这个小题

简介: 看我如何用两只兔子解决这个小题

看我如何用两只兔子解决这个小题

一、题目描述

给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

示例 2:

输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

提示:

  • 给定链表的结点数介于 1100 之间。

二、思路分析

先从最简单的思路说起,想要知道中间节点,首先要知道链表长度信息。

但是从题目信息,我们只得知这是一个单链表,并不知道它的长度信息。

这时候就可以考虑先遍历一遍链表的节点,统计一下链表的长度,然后再求出中位数,这时候就可以获取中间节点了。

代码实现

class Solution {
    public ListNode middleNode(ListNode head) {
        // 遍历获取链表长度
        ListNode temp = head;
        int n = 0;
        while (temp != null) {
            ++n;
            temp = temp.next;
        }
        // 获取中间节点的位置
        int middle = (n >> 1) + 1;
        // 移动到中间节点
        while (middle > 1) {
            head = head.next;
            --middle;
        }
        return head;
    }
}

从代码实现中,我们可以看出空间复杂度为O(1),时间复杂度为O(n)

那么是不是还有更加优雅的方法呢?


小伙伴们,我们先来做个小学算术题:在一条笔直笔直的小路上,大白兔和小白兔赛跑,已知大白兔的速度是小白兔的两倍,小白兔从小路中点起跑,大白兔从小路起点起跑,它们两个能否在小路终点相遇呢?

答案是肯定会相遇的,这个都能想明白。

现在小白兔和大白兔要折返回来,请问一下,大白兔跑回起点的时候,小白兔跑到了什么位置呢?没错,就是中点,也就是这题的关键解法~~~

创建快慢指针,当快指针到达终点的时候,慢指针正好到达起点位置。而且快慢指针只需要遍历一边链表,相对于上面的计算长度的解法来说少了第二次查找中间位置的操作。

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode bigRabbit = head;
        ListNode smallRabbit = head;
        // 这一步很重要,一定要判断清楚,哪一个节点不能为空
        while (bigRabbit != null && bigRabbit.next != null) {
            smallRabbit = smallRabbit.next;
            bigRabbit = bigRabbit.next.next;
        }
        return smallRabbit;
    }
}

从代码实现中,我们可以看出空间复杂度为O(1),时间复杂度为O(n)

三、总结

关于链表的问题,基本上就是遍历链表解题的操作,如果遇到需要遍历多次的情况,可以优先考虑是否能用多个指针,每个指针代表一次遍历,从而减少遍历的次数,提高查询效率。

目录
相关文章
Error: listen EACCES: permission denied 0.0.0.0:80
Error: listen EACCES: permission denied 0.0.0.0:80
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
592 7
数据结构电梯模拟 不限电梯数 不限楼层数 100梯1000层
本文提供数据结构教材习题 “电梯模拟” 的一种解答。
|
运维 监控 测试技术
软件体系结构 - 系统工程【霍尔三维结构】
软件体系结构 - 系统工程【霍尔三维结构】
854 0
|
SQL 关系型数据库 MySQL
在Linux中,如何实现数据备份和恢复?
在Linux中,如何实现数据备份和恢复?
|
监控
观察者效应
观察者效应
1081 2
|
存储 固态存储 内存技术
计算机硬件的基本组成与工作原理
计算机硬件的基本组成与工作原理
|
Java
SpringSecurity-6-基于Filter实现图形验证码
SpringSecurity中有多种方式实现图像验证码,使用自定义过滤器去处理验证码逻辑是最简单的方式,只要将过滤器添加到合适的位置,当登录的时候,对验证码进行校验,成功就放行,失败则抛出异常。
307 0
|
前端开发 JavaScript UED
使用 Tree Shaking 精简你的前端代码
在现代 Web 开发中,前端性能优化是一个关键的课题。优化代码大小和加载时间对于提供优秀的用户体验至关重要。Tree Shaking 技术成为了解决这一问题的重要工具。本文将介绍 Tree Shaking 技术的原理、优点和缺点,以及在知名项目中的使用场景,帮助初学者快速掌握这一技术
458 0
|
测试技术
Appium 并行测试多个设备
Appium 并行测试多个设备
491 0