LeetCode题练习与总结:回文链表--234

ops/2024/9/23 3:53:26/

一、题目描述

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

示例 1:

输入:head = [1,2,2,1]
输出:true

示例 2:

输入:head = [1,2]
输出:false

提示:

  • 链表中节点数目在范围[1, 10^5] 内
  • 0 <= Node.val <= 9

二、解题思路

  1. 快慢指针法找到链表中点:我们可以使用两个指针,快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针恰好到达链表中点。

  2. 翻转后半部分链表:当找到链表中点后,我们可以将后半部分链表翻转,以便与前半部分链表进行比较。

  3. 比较前后两部分链表:将前半部分链表与翻转后的后半部分链表进行比较,如果每个节点的值都相等,则为回文链表

  4. 恢复链表(可选):如果题目要求不改变原链表结构,我们需要在比较完成后,将后半部分链表再次翻转回来。

三、具体代码

class Solution {public boolean isPalindrome(ListNode head) {// 快慢指针找到链表中点ListNode slow = head, fast = head;while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;}// 如果链表长度为奇数,慢指针需要再向前移动一位if (fast != null) {slow = slow.next;}// 翻转后半部分链表ListNode prev = null;ListNode curr = slow;while (curr != null) {ListNode nextTemp = curr.next;curr.next = prev;prev = curr;curr = nextTemp;}// 比较前后两部分链表ListNode firstHalf = head;ListNode secondHalf = prev;while (secondHalf != null) {if (firstHalf.val != secondHalf.val) {return false;}firstHalf = firstHalf.next;secondHalf = secondHalf.next;}return true;}
}

注意:在比较完成后,如果题目没有要求恢复原链表结构,则不需要再次翻转后半部分链表。如果需要恢复,可以在比较完成后,将上述翻转后半部分链表的代码再执行一遍。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 快慢指针遍历链表:这个步骤中,快指针每次移动两步,慢指针每次移动一步,直到快指针到达链表末尾。在最坏的情况下,快指针会遍历整个链表一次,而链表长度为 n,所以时间复杂度为 O(n)。

  • 翻转后半部分链表:这个步骤中,我们需要遍历链表的后半部分,也就是大约 n/2 个节点,因此时间复杂度为 O(n/2),这可以简化为 O(n)。

  • 比较前后两部分链表:在这个步骤中,我们比较前后两部分链表,每部分大约有 n/2 个节点,因此时间复杂度为 O(n/2),这同样可以简化为 O(n)。

将上述步骤的时间复杂度相加,我们得到总的时间复杂度为 O(n) + O(n) + O(n) = O(n)。

2. 空间复杂度
  • 快慢指针遍历链表:这个步骤中,我们只使用了常数个额外空间(即快慢指针),因此空间复杂度为 O(1)。

  • 翻转后半部分链表:在这个步骤中,我们没有使用额外的数据结构,而是直接在原链表上进行操作,所以空间复杂度仍然是 O(1)。

  • 比较前后两部分链表:这个步骤中,我们也没有使用额外的空间,只是通过指针遍历链表,所以空间复杂度为 O(1)。

将上述步骤的空间复杂度相加,我们得到总的空间复杂度为 O(1) + O(1) + O(1) = O(1)。

综上所述,该算法的时间复杂度为 O(n),空间复杂度为 O(1)。

五、总结知识点

  • 链表(Linked List)

    • 链表是一种常见的基础数据结构,由一系列节点组成,每个节点包含数据域和指向下一个节点的指针。
  • 链表(Singly Linked List)

    • 代码中的链表是单链表,每个节点只包含一个指向下一个节点的指针。
  • 快慢指针(Fast and Slow Pointers)

    • 快慢指针是一种技巧,常用于解决链表中的问题,如查找链表中点、检测环等。快指针每次移动两步,慢指针每次移动一步。
  • 链表翻转(Reversing a Linked List)

    • 代码展示了如何通过迭代的方式翻转链表的一部分。这是通过改变节点指针的方向来实现的。
  • 递归(Recursion)

    • 虽然代码中没有直接使用递归,但翻转链表的过程也可以通过递归来实现。
  • 迭代(Iteration)

    • 代码中使用了迭代(循环)来翻转链表的后半部分以及比较链表的前后两部分。
  • 边界条件处理

    • 在快慢指针寻找中点的过程中,代码处理了链表长度为奇数的情况,确保慢指针正确地指向后半部分链表的第一个节点。
  • 逻辑判断(Logical Comparison)

    • 代码中使用了 if 语句来比较链表前后两部分节点的值,以判断链表是否为回文。
  • 链表节点类定义(ListNode Class Definition)

    • 虽然代码片段中没有给出 ListNode 类的定义,但它是链表实现的基础,通常包含一个数据域和一个指向下一个节点的指针。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。


http://www.ppmy.cn/ops/114567.html

相关文章

python函数的一些介绍

函数的多返回值 def 函数(): return 1,2,3 x,y,z 函数&#xff08;&#xff09;#对应1&#xff0c;2&#xff0c;3 有几个就要有对应的几个变量存储&#xff0c;不然会报错 函数的关键字参数 def 函数&#xff08;name,id&#xff09;&#xff1a; 打印输出name和id 函数…

CSAPP Bomb Lab

本 Lab 可以说是 CSAPP 的几个 Lab 中最为人津津乐道的一个&#xff0c;对应知识点为书中的第 3 章&#xff08;程序的机器级表示&#xff09;&#xff0c;要求使用 GDB 调试器&#xff0c;对汇编语言进行调试&#xff0c;从而得出正确的“拆弹密码”。共分为 6 个关卡和一个隐…

Android 命令行关机

在 Android 设备上&#xff0c;可以通过以下命令行命令来关机&#xff1a; adb shell reboot -p其中&#xff1a; adb shell&#xff1a;通过 ADB 进入设备的命令行环境。reboot -p&#xff1a;执行关机操作&#xff0c;-p 表示关机而不是重启。 如果你是在设备本地的终端上而…

Linux(Centos7)系统下给已有分区进行扩容

本文详细介绍了&#xff0c;如何给Centos中已有分区进行扩容&#xff0c;简单的几条命令即可完成。 文章目录 1. 创建物理卷 (PV)2. 将新的物理卷添加到卷组 (VG)3. 扩展逻辑卷 (LV)4. 扩展文件系统4.1 查看文件系统类型4.2 扩展文件系统 完成 1、首先把vmware中的linux关机&am…

第三章 掌握MySQL数据库的基本操作

文章目录 一、关系数据库标准语言SQL1.1 SQL的发展历史与特点1.2 SQL的分类 二、数据库的管理2.1 创建数据库2.2 查看数据库2.3 选择数据库2.4 删除数据库 三、MySQL存储引擎3.1 MySQL支持的存储引擎3.2 InnoDB存储引擎3.3 MyISAM存储引擎3.4 选择存储引擎 四、表的管理4.1 数据…

AUTOSAR UDS NRC

UDS NRC NRC 含义如表格所示 NRC代码描述含义0x00Ok没有错误,请求已成功执行0x01~0x0FISOSAEReservedISO 保留,暂时未定义0x10General reject服务请求被拒绝,原因不明确0x11Service not supported请求的服务不被支持0x12Sub-function not supported请求的子功能不被支持0x13…

Linux bash 关联数组

目录 一. 关联数组定义二. 访问关联数组三. 元素的添加与删除四. 键值对的获取与遍历五. 实际应用5.1 读取封装配置文件内容5.2 收集系统信息 一. 关联数组定义 从 Bash 4.0 开始&#xff0c;Bash 支持关联数组。关联数组允许你将键和值配对&#xff0c;并通过键来访问值&…

TCP socket

TCP的socket和UDP大同小异&#xff0c;基本的代码结构都是相同的。一些相同的接口本文就不赘述了&#xff0c;例如&#xff0c;socket,bind&#xff0c;有需要看这篇文章UDP socket 服务端server 两步&#xff1a;初始化服务端&#xff0c;运行服务端 初始化服务端 创建soc…