funcisPalindrome(head *ListNode)bool { // 处理边界情况 if head == nil || head.Next == nil { returntrue }
// 查找链表中点 fast, slow := head, head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next }
// 处理奇数长度链表的情况 var secondHalf *ListNode if fast == nil { // 偶数长度 secondHalf = slow } else { // 奇数长度,中间节点不参与比较 secondHalf = slow.Next } // 断开链表 firstHalfEnd := slow if fast == nil { firstHalfEnd = findPredecessor(head, slow) } firstHalfEnd.Next = nil // 反转后半部分 secondHalf = reverseList(secondHalf)
// 比较两半部分 result := compareHalves(head, secondHalf) // 可选:恢复链表结构 // firstHalfEnd.Next = reverseList(secondHalf) return result }
// 找到前驱节点 funcfindPredecessor(head, target *ListNode) *ListNode { if head == target { returnnil } curr := head for curr != nil && curr.Next != target { curr = curr.Next } return curr }
// 比较两个链表 funccompareHalves(first, second *ListNode)bool { for first != nil && second != nil { if first.Val != second.Val { returnfalse } first = first.Next second = second.Next } returntrue }
// 反转链表 funcreverseList(head *ListNode) *ListNode { var prev *ListNode curr := head for curr != nil { next := curr.Next curr.Next = prev prev = curr curr = next } return prev }
方法五:递归解法
递归方法也可以用来解决此问题,但需要 O(n) 的栈空间。
实现细节
使用递归遍历到链表末尾
回溯时,与前面的节点比较
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
funcisPalindrome(head *ListNode)bool { frontPointer := head var recursiveCheck func(*ListNode)bool recursiveCheck = func(currentNode *ListNode)bool { if currentNode != nil { if !recursiveCheck(currentNode.Next) { returnfalse } if frontPointer.Val != currentNode.Val { returnfalse } frontPointer = frontPointer.Next } returntrue } return recursiveCheck(head) }
Comparison of Approaches
方面
方法一:数组
方法二:栈
方法三:原始反转
方法四:优化反转
方法五:递归
时间复杂度
O(n)
O(n)
O(n)
O(n)
O(n)
空间复杂度
O(n)
O(n)
O(1)
O(1)
O(n)
优点
实现简单
直观易懂
空间效率高
代码健壮,易于理解
简洁优雅
缺点
空间开销大
空间开销大
代码结构不够清晰
略微复杂
使用了隐式栈空间
推荐度
★★☆☆☆
★★☆☆☆
★★★★☆
★★★★★
★★★☆☆
Complexity Analysis
时间复杂度
所有方法的时间复杂度都是 O(n),其中 n 是链表的长度。这是因为所有方法都需要至少遍历一次链表。