返回
234 回文链表,以别开生面的方式七天打卡
闲谈
2024-01-03 02:18:01
LeetCode 的 234 回文链表问题,就是要你判断一个链表是否为回文链表,如果题目里没限制额外空间的话,那问题基本等同于字符串判断是否是回文串,按套路应该是把链表所有元素都读到数组里,再双指针比较。但是作为 leetcode 训练,要求尽可能的利用题目限制优化复杂度,甚至是优化时间复杂度。这也是我本人特别推荐的一道题,对加深理解算法相关概念和提升算法能力都很重要。
我们来一步一步拆分算法:
1、明确回文链表的性质:
- 回文链表的特点是,正序读和倒序读都是一样的。
- 也就是说,从头结点开始读,依次读到尾结点;从尾结点开始读,依次读到头结点,这两个过程读到的值是一样的。
2、设计算法流程:
- 将链表分成两段,一段从头结点到中间结点,另一段从中间结点的下一个结点到尾结点。
- 将后一段链表反转。
- 比较两段链表的值是否相等。
- 将后一段链表再反转回来,恢复原样。
3、算法实现:
- 找到链表的中间结点。
- 将链表从中间结点处断开。
- 将后一段链表反转。
- 比较两段链表的值是否相等。
- 将后一段链表再反转回来,恢复原样。
4、算法分析:
- 时间复杂度:O(n),因为我们遍历了链表两次。
- 空间复杂度:O(1),因为我们没有使用额外的空间。
5、代码实现:
def isPalindrome(head):
if not head or not head.next:
return True
# 找到链表的中间结点
slow = head
fast = head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 将链表从中间结点处断开
mid = slow.next
slow.next = None
# 将后一段链表反转
prev = None
curr = mid
while curr:
next = curr.next
curr.next = prev
prev = curr
curr = next
# 比较两段链表的值是否相等
while mid:
if mid.val != head.val:
return False
mid = mid.next
head = head.next
# 将后一段链表再反转回来,恢复原样
prev = None
curr = mid
while curr:
next = curr.next
curr.next = prev
prev = curr
curr = next
return True
6、更优的解决方案:
上述算法的时间复杂度为 O(n),空间复杂度为 O(1)。我们可以通过使用快慢指针来找到中间结点,从而将时间复杂度降低到 O(n/2)。
def isPalindrome(head):
if not head or not head.next:
return True
# 使用快慢指针找到中间结点
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 将链表从中间结点处断开
mid = slow
slow.next = None
# 将后一段链表反转
prev = None
curr = mid
while curr:
next = curr.next
curr.next = prev
prev = curr
curr = next
# 比较两段链表的值是否相等
while mid:
if mid.val != head.val:
return False
mid = mid.next
head = head.next
# 将后一段链表再反转回来,恢复原样
prev = None
curr = mid
while curr:
next = curr.next
curr.next = prev
prev = curr
curr = next
return True
这样一来,算法的时间复杂度就降到了 O(n/2)。
7、结语:
通过本文,您已经了解了如何判断一个链表是否为回文链表。我们从回文链表的性质出发,一步步推导出算法流程,并提供了两种不同实现方式。希望您能从中有所收获,并运用到实际项目中。