《程序员面试金典(第6版)》面试题 02.06. 回文链表(双指针(快慢指针),查找链表中间节点,反转链表)

news/2025/2/23 22:05:29

题目描述

编写一个函数,检查输入的链表是否是回文的。
题目传送门~:面试题 02.06. 回文链表

示例 1:

输入: 1->2
输出: false 

示例 2:

输入: 1->2->2->1
输出: true 

进阶:

  • 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解题思路与代码

  • 这是一道有关链表操作的题,不算特别的难。考到了链表的几个基础的操作,像是反转链表,创建一个新的链表,找到链表的中间节点,用什么方式去找。
  • 所以,需要你对链表的基础操作有一定的理解,如果你对链表的操作了熟于心的话,这道题真的是简单的不在话下,但是如果对链表只是基本了解的话,这道题还是有一丢丢难度的。

方案一:构造一条新链表(原链表的反转)之后对比

  • 这里有一点十分需要注意的是:这里的反转链表,不是在原链表上进行反转操作,而是创建一个新链表,新链表的内容是反转后的原链表,之后我们才可以继续对比操作。
  • 很多新手,或者说对链表不熟悉的人来说,很容易就 ListNode * prev = head; 开始准备反转链表了,殊不知它们已经修改了原链表的内容了,拿着修改后的原链表与自己做对比,那不就100%会出错嘛~

具体的代码如下:

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        // 创建前驱节点,并且为重新创建一条新的链表(节点反转后的链表)做准备
        ListNode * tail = head;
        ListNode * newHead = nullptr;
        // 创建一条链表(节点反转后的链表
        while(tail){
            ListNode * temp = new ListNode(tail->val);
            temp->next = newHead;
            tail = tail->next;
            newHead = temp;
        }

        // 检查两条链表是否相等,若相等则返回true,否则false
        while(newHead) {
            if(newHead->val != head->val) return false;
            head = head->next;
            newHead = newHead->next;
        }
        
        return true;
    }
};

在这里插入图片描述

复杂度分析

时间复杂度:
该代码包含两个循环。第一个循环遍历整个链表以创建一个反向链表。第二个循环遍历链表以比较原始链表和反向链表的节点。因此,总的时间复杂度为O(n) + O(n) = O(2n),在大O表示法中,我们忽略常数,所以时间复杂度为O(n)。

空间复杂度:
在创建反向链表的过程中,为每个节点分配了新的内存,所以空间复杂度为O(n),其中n为链表的长度。

方案二:优化,快慢指针!

  • 这个方案,我们使用快慢指针的方式,先找到这个链表的中间节点,紧接着,反转后半部分的链表,之后就进行对比就可以了。
  • 由于是在原链表上面进行操作,空间复杂度可以降低到O(1)
  • 快慢指针找到中间节点的好处是,不用去管奇数还是偶数节点。如果你还不理解的话,请你在纸上画一画草图,离开就能出来了。

具体的代码如下:

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == nullptr || head->next == nullptr) return true;
        ListNode * slow = head;
        ListNode * fast = head;
        // 找到中间节点
        while(fast->next != nullptr && fast->next->next != nullptr){
            slow = slow->next;
            fast = fast->next->next;
        }
        // 反转后半链表
        ListNode * prev = nullptr;
        while(slow != nullptr){
            ListNode * temp = slow->next;
            slow->next = prev;
            prev = slow;
            slow = temp;
        }

        // 开始逐一对比
        while(head != nullptr && prev !=nullptr){
            if(head->val != prev->val) return false;
            head = head->next;
            prev = prev->next;
        }
        return true;
    }
};

在这里插入图片描述

复杂度分析

时间复杂度:

  • 这段代码包含三个主要步骤:找到链表的中点,反转链表的后半部分,然后比较两个半链表。这三个步骤都需要遍历链表,所以总的时间复杂度是 O(n) + O(n) + O(n) = O(3n)。但在大O表示法中,我们会忽略常数,所以最终的时间复杂度是O(n)。

空间复杂度:

  • 这段代码并没有使用额外的空间来存储链表的节点。所有的操作都是在原来链表的基础上完成的,所以空间复杂度是O(1)。

总结

这道题目是关于链表操作和回文识别的。链表是一种常用的数据结构,而回文是一种对称的特性,出现在很多算法和数据结构问题中。该题目测试了你对链表操作的理解,以及你对如何使用常量空间来解决问题的理解。

对于这道题的实际意义,可以从以下几个方面理解:

  • 对数据结构的理解和操作链表是一种基础且常用的数据结构,理解和掌握链表的操作是非常重要的。这道题测试了你对链表的理解和操作能力。

  • 算法设计:这道题目需要你设计一个算法来解决问题。这考察了你的问题解决能力,包括如何将问题分解,如何设计算法,以及如何实现算法。

  • 空间复杂度优化:题目进阶部分要求使用 O(1) 的空间复杂度来解决问题,这就需要你考虑如何在不增加额外空间的情况下解决问题。这是对你优化代码和理解空间复杂度的一个测试。

  • 时间复杂度的理解:题目要求算法的时间复杂度为 O(n),这就需要你保证你的算法在最坏的情况下也能在线性时间内完成。

  • 实际应用:在实际的软件开发中,我们可能会遇到需要判断一个序列是否为回文的情况,例如检测字符串是否为回文。此题就可以作为实现该功能的一种思路。

所以,这道题目的主要意义在于锻炼和测试你的数据结构操作能力,算法设计能力,以及你对时间和空间复杂度的理解。同时,也可以帮助你在实际问题中更好地应用这些技巧和知识。

最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容


http://www.niftyadmin.cn/n/349378.html

相关文章

【MySQL】-【数据库的设计规范】

文章目录 为什么需要数据库设计范式范式简介范式都包括哪些键和相关属性的概念第一范式(1st NF)第二范式(2nd NF)第三范式(3rd NF) 反范式化概述应用举例反范式化的新问题反范式的适用场景 BCNF(巴斯范式)案例 为什么需要数据库设计 范式 范式简介 在关系型数据库中&#xff…

v-model使用及原理

关于v-model,vue2与vue3用法不一致,本文学习采用了vue3官网文档。与vue2区别写在本文末尾。一、为什么使用v-model? v-model指令可以在表单input、textarea以及select元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素…

可视化翻转教学python

目录 第1关 绘制折线图 第2关 绘制正弦曲线 第3关 绘制指定线型、颜色和标记的正弦曲线 第4关 定义绘制正余弦函数曲线的函数 第5关 绘制坐标轴并设置范围 第1关 绘制折线图 显示绘制结果 plt.show():用于显示绘制的结果,无参数,执行此…

mysql子查询嵌套

目录 前言 一、实际需求解决 1.方式1:自连接 2.方式2:子查询 二、单行子查询 1.操作符子查询 三、相关子查询 四、自定义语句 五、子查询的问题 1.空值问题 2.非法使用子查询 六、多行子查询 七、聚合函数的嵌套使用 八、多行子查询空值问题…

LeetCode高频算法刷题记录8

文章目录 1. 零钱兑换【中等】1.1 题目描述1.2 解题思路1.3 代码实现 2. 最小栈【最小栈】2.1 题目描述2.2 解题思路2.3 代码实现 3. 最长有效括号【困难】3.1 题目描述3.2 解题思路3.3 代码实现 4. 从前序与中序遍历序列构造二叉树【中等】4.1 题目描述4.2 解题思路4.3 代码实…

【牛客刷题专栏】0x29:JZ31 栈的压入、弹出序列(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转),它登陆后会保存刷题记录进度,重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏:个人CSDN牛客刷题专栏。 题目来自:牛客/题库 / 在线编程 / 剑指offer: 目录 前言问…

物联网时代,从智能咖啡机到车联网都可能被黑!

"伴随5G明年即将正式商转,物联网(IoT)时代特有的“万物皆联网”景况也近在咫尺,届时x连网对象数量将呈现猛爆增长。物联网技术的前期采用者,除了加速物联网基础建设与创新技术应用导入之外,也面临更广泛的安全管理风险与更严…

uni-app之使用App.vue全局文件的教学

在 UniApp 中,App.vue 是整个应用的入口文件,它可以作为一个全局文件,在其中定义的数据、方法和生命周期钩子可以在整个应用中使用。这篇文章将向您介绍如何使用 App.vue 文件来实现全局信息的共享和管理。 步骤: 创建 App.vue 文…