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

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

相关推荐
sin_hielo2 小时前
leetcode 3228
算法·leetcode
嫂子的姐夫2 小时前
23-MD5+DES+Webpack:考试宝
java·爬虫·python·webpack·node.js·逆向
青山的青衫3 小时前
【Java基础07】链表
java·开发语言·链表
麦麦鸡腿堡3 小时前
Java事件处理机制
java·开发语言·python
xier_ran3 小时前
力扣(LeetCode)100题:41.缺失的第一个正数
数据结构·算法·leetcode
Swift社区3 小时前
LeetCode 425 - 单词方块
算法·leetcode·职场和发展
谅望者3 小时前
数据分析笔记07:Python编程语言介绍
大数据·数据库·笔记·python·数据挖掘·数据分析
Geo_V4 小时前
LangChain Memory 使用示例
人工智能·python·chatgpt·langchain·openai·大模型应用·llm 开发
weixin_307779134 小时前
软件演示环境动态扩展与成本优化:基于目标跟踪与计划扩展的AWS Auto Scaling策略
算法·云原生·云计算·aws