数据结构与算法之 leetcode 链表回文判断 双指针 + 栈

数据结构与算法阿木 发布于 4 天前 2 次阅读


链表回文判断:双指针与栈的巧妙运用

在数据结构与算法的学习过程中,链表是一种非常重要的数据结构。链表具有灵活的插入和删除操作,但在某些情况下,链表也会带来一些挑战,例如判断链表是否为回文结构。本文将围绕这一主题,探讨如何使用双指针和栈两种方法来判断链表是否为回文。

链表回文判断问题

给定一个链表,判断该链表是否为回文结构。回文结构是指从前往后读和从后往前读都相同的结构。

方法一:双指针

原理

双指针法的基本思想是使用两个指针,一个从链表头部开始遍历,另一个从链表尾部开始遍历。当两个指针相遇时,如果链表是回文结构,则两个指针所指向的元素应该相同。

代码实现

python

class ListNode:


def __init__(self, val=0, next=None):


self.val = val


self.next = next

def is_palindrome(head):


快慢指针


slow = fast = head


找到链表的中点


while fast and fast.next:


slow = slow.next


fast = fast.next.next


如果链表长度为奇数,跳过中间的节点


if fast:


slow = slow.next


反转后半部分链表


prev = None


while slow:


next_node = slow.next


slow.next = prev


prev = slow


slow = next_node


比较前半部分和反转后的后半部分


left, right = head, prev


while right:


if left.val != right.val:


return False


left = left.next


right = right.next


return True


分析

- 时间复杂度:O(n),其中n为链表长度。需要遍历整个链表。

- 空间复杂度:O(1),不需要额外的空间。

方法二:栈

原理

栈是一种后进先出(LIFO)的数据结构。我们可以将链表的前半部分元素依次入栈,然后从链表尾部开始遍历,每次将遍历到的元素与栈顶元素进行比较。如果所有元素都相同,则链表为回文结构。

代码实现

python

class ListNode:


def __init__(self, val=0, next=None):


self.val = val


self.next = next

def is_palindrome(head):


stack = []


current = head


将链表的前半部分元素入栈


while current and len(stack) < len(list(head)):


stack.append(current.val)


current = current.next


如果链表长度为奇数,跳过中间的节点


if current:


current = current.next


比较栈顶元素和链表剩余元素


while current:


if stack.pop() != current.val:


return False


current = current.next


return True


分析

- 时间复杂度:O(n),其中n为链表长度。需要遍历整个链表。

- 空间复杂度:O(n),需要额外的空间来存储栈。

总结

本文介绍了两种判断链表是否为回文结构的方法:双指针和栈。双指针法在空间复杂度上具有优势,而栈法在代码实现上更为简单。在实际应用中,可以根据具体需求选择合适的方法。

扩展

除了上述两种方法,还可以使用递归法来判断链表是否为回文结构。递归法的基本思想是将链表分为两部分,递归判断前半部分和后半部分是否相同。这种方法在代码实现上较为复杂,但可以更好地理解递归的概念。

链表回文判断是一个有趣且具有挑战性的问题。通过学习双指针和栈的应用,我们可以更好地掌握链表的操作,并提高编程能力。