LeetCode hot100:234 回文链表:快慢指针巧判回文链表

问题描述:

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

示例1:

**输入:**head = [1,2,2,1]

**输出:**true

示例2:

**输入:**head = [1,2]

**输出:**false

解决方法:

方法一:数组+双指针

算法思路:

  1. 遍历链表,将节点值复制到数组中;

  2. 使用双指针法判断数组是否为回文。

代码实现:

python 复制代码
def isPalindrome(head):
    values = []
    curr = head
    while curr:
        values.append(curr.val)
        curr = curr.next
    
    left, right = 0, len(values) - 1
    while left < right:
        if values[left] != values[right]:
            return False
        left += 1
        right -= 1
    return True

复杂度分析:

  • 时间复杂度:O(n),需要遍历链表和数组各一次
  • 空间复杂度:O(n),需要额外的数组空间存储节点值

方法二:快慢指针+翻转

算法思路:

  1. 使用快慢指针找到链表中点;

  2. 反转后半部分链表;

  3. 比较前半部分和反转后的后半部分。

代码实现:

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        # 快慢指针
        if not head or not head.next:
            return True
        fast = low = head
        # 查找反转的起点
        while fast and fast.next:
            low = low.next
            fast = fast.next.next
        # 反转后半部分链表
        prev = None
        cur = low
        while cur: # 迭代反转
            nxt = cur.next
            cur.next = prev
            prev = cur
            cur = nxt
        # 链表比较
        left = head
        right = prev
        while right:
            if left.val != right.val:
                return False
            left = left.next
            right = right.next
        return True

复杂度分析:

  • 时间复杂度:O(n),遍历链表的次数是常数倍
  • 空间复杂度:O(1),只使用了几个指针变量

问题详解:

以链表 [ 1,2,3,2,1]为例说明方法二:

1、快慢指针找中点:

  • 慢指针每次走1步,快指针每次走2步;
  • 最终慢指针会停在节点3上。

2、反转后半部分:

  • 将 [3,2,1]反转为[1,2,3];
  • 此时链表的结构被修改,但比较阶段不需要完整的结构。

3、比较前后部分:

  • 前半部分: [1,2,3];
  • 后半部分(反转后):[1,2,3];
  • 逐个比较对应节点值。

关键点说明

  • 为什么在比较部分要使用 ++while right:++后半部分长度总是整体的一部分,小于等于前半部分长度,确保只比较必要的节点对数;
  • 链表的结构改变:方法二会改变链表的结构,但是比较完成后通常不需要恢复;
  • 边界情况处理:空链表和单节点链表直接返回 true。

总结:

| 方法 | 优点 | 缺点 | 适用情况 |
| 数组+双指针 | 思路简单,不易出错 | 需要额外O(n)空间 | 对空间要求不高的场景 |

快慢指针+翻转 空间复杂度O(1) 会修改原链表结构 对空间有严格要求的场景

通常情况下期望掌握第二种方法,因为它展示了更多的链表操作技巧。

相关推荐
qq_1898070311 小时前
mysql如何查看所有数据库用户_mysql用户查询管理命令
jvm·数据库·python
hhhhhh_we11 小时前
预颜美历:AI驱动的私人面部美学与皮肤全周期管理工具
前端·图像处理·人工智能·python·aigc
xiaotao13111 小时前
01-编程基础与数学基石:线性代数
人工智能·python·线性代数
光泽雨11 小时前
c#数值类型之间的自动转换
java·算法·c#
ZPC821011 小时前
moveit2 servo -movegroup aciton client arm_controller -rviz2
人工智能·算法·计算机视觉·机器人
石工记11 小时前
基于LangGraph实现智能分诊系统
数据库·人工智能·python·ai编程
m0_6403093011 小时前
Redis怎样优化客户端拉取拓扑的频率_在客户端层面捕获MOVED异常时才触发全局路由表刷新
jvm·数据库·python
亚林瓜子11 小时前
AWS Glue Python Shell任务中获取AWS SM中的加密配置
python·aws·glue·sm
214396511 小时前
如何利用RMAN修复逻辑坏块_VALIDATE CHECK LOGICAL验证块内结构损坏
jvm·数据库·python
qq_2069013911 小时前
如何使用 AWS Lambda 和 Python 获取 EMR 集群的标签列表
jvm·数据库·python