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) 会修改原链表结构 对空间有严格要求的场景

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

相关推荐
会员源码网4 小时前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing5 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader6 小时前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱8 小时前
二叉树分解问题思路解题模式
javascript·后端·算法
zone77398 小时前
001:简单 RAG 入门
后端·python·面试
F_Quant8 小时前
🚀 Python打包踩坑指南:彻底解决 Nuitka --onefile 配置文件丢失与重启报错问题
python·操作系统
允许部分打工人先富起来9 小时前
在node项目中执行python脚本
前端·python·node.js
IVEN_9 小时前
Python OpenCV: RGB三色识别的最佳工程实践
python·opencv
qianpeng89710 小时前
水声匹配场定位原理及实验
算法
haosend10 小时前
AI时代,传统网络运维人员的转型指南
python·数据网络·网络自动化