力扣Hot100--234.回文链表
力扣Hot100–234.回文链表
要求:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
解题思路:
1、将链表节点值存储在列表中
2、然后使用了双指针法从列表两端向中间比较节点的值
在python中 mode_set[::-1] 表示将列表 vals反转了,所以也可以通过 mode_set==mode_set[::-1] 来判断是否是一个回文列表。这里要注意,那mode_set 就要保存节点的值,并非节点本身!!!
时间复杂度:O(n),遍历链表一次,比较列表一次
空间复杂度:O(n),需要额外空间存储所有节点值
常见方法:递归法和快慢指针法
代码:
# 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:mode_set = []current = headwhile current:mode_set.append(current)current=current.nextleft,right = 0,len(mode_set)-1while left<right:if mode_set[left].val != mode_set[right].val:return False left = left+1right= right-1return True
递归法:
1、递归调用会沿着 current_node.next一路向下,直到链表末尾,直到末尾就会return True;
2、然后if not …判断的是内层递归的比较结果。如果内层递归在比较过程中发现了任何不匹配(即返回了 False),那么当前递归函数会立即将这个 False结果返回,不再执行后续的比较(包括 if current_node.val != self.front_pointer.val的判断),从而快速结束递归,向外部传递“不是回文”的信号。
3、如果是回文的话会返回 True,然后外部的front_pointer 会逐步向后移动。
时间复杂度:O(n),其中 n 是链表的长度。每个节点都会被访问一次。
空间复杂度:O(n),主要用于递归调用栈。递归深度与链表长度 n 成正比。
class Solution:def isPalindrome(self, head: Optional[ListNode]) -> bool:self.front_pointer = head return self.func(head)def func(self,current_node):if current_node is not None:if not self.func(current_node.next):return False if current_node.val != self.front_pointer.val:return Falseself.front_pointer = self.front_pointer.nextreturn True
快慢指针: 重点关注!!!
1、使用快慢指针,快指针一次走两步,慢指针一次走一步。当快指针到达末尾时,慢指针位于链表中点(奇数长度)或前半部分末尾(偶数长度);
2、从慢指针指向的节点开始反转后半部分链表;
3、同时遍历前半部分和反转后的后半部分,比较每个节点的值。如果所有值都相等,则是回文链表;
4、最后将链表恢复原样–虽然题目没要求
时间复杂度是 O(n)
空间复杂度是 O(1)
class Solution:def isPalindrome(self, head: Optional[ListNode]) -> bool:if not head or not head.next:return Trueslow = headfast = headwhile fast and fast.next:slow = slow.nextfast = fast.next.next# 反转后半部分链表。slow此时位于中点或前半部分末尾,slow.next是后半部分的起点second_half_head = self.reverseList(slow) # 反转后,second_half_head成为反转后的头节点first_half_head = head # 前半部分的头节点仍然是head# 比较前半部分和反转后的后半部分# 注意:无论链表长度是奇是偶,反转后的后半部分长度 <= 前半部分长度p1 = first_half_headp2 = second_half_headis_palindrome = Truewhile p2: # 只需遍历反转后的后半部分即可if p1.val != p2.val:is_palindrome = Falsebreakp1 = p1.nextp2 = p2.next# 恢复链表结构slow.next = self.reverseList(second_half_head)return is_palindromedef reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:pre = Nonecur = headwhile cur:temp = cur.nextcur.next = prepre = curcur = tempreturn pre