https://leetcode.cn/problems/palindrome-linked-list/
(1)将链表转化为数组进行比较
比较呆板的做法,空间复杂度为O(n)
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : bool isPalindrome (ListNode* head) { vector<int > arr; ListNode* p = head; while (p) { arr.push_back (p->val); p = p->next; } int n = arr.size (); for (int i = 0 , j = n - 1 ; i < j; i++, j--) { if (arr[i] != arr[j]) return false ; } return true ; } };
(2)递归
链表也具有递归性质,二叉树也不过是链表的衍生。
利用后序遍历 的思想:
先保存头结点(left,全局变量),然后递归至最后(最深)的结点(right),然后比较left
和right
的值;如果相等,由递归栈返回上一层(也即right向左走),再操作left向右走,这样就实现了left和right的双向奔赴。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {private : ListNode* left_ = nullptr ; bool Traverse (ListNode* right) { if (!right) return true ; bool res = Traverse (right->next); res = res && (left_->val == right->val); left_ = left_->next; return res; } public : bool isPalindrome (ListNode* head) { left_ = head; return Traverse (head->next); } };
(3)优化递归
利用方法二,看似是没有使用到额外空间了,但实际上还有递归所带来的函数调用栈的开销,其空间复杂度也为O(n)
。
因此可以利用双指针 的思想,找到链表的中间结点后,将其后面的结点反转。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 using ListNodePtr = ListNode*;class Solution {private : ListNode* Reverse (ListNode* head) { ListNodePtr cur = head, pre = nullptr ; while (cur) { ListNodePtr ne = cur->next; cur->next = pre; pre = cur; cur = ne; } return pre; } public : bool isPalindrome (ListNode* head) { ListNodePtr fast = head, slow = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } if (fast) slow = slow->next; ListNodePtr left = head; ListNodePtr right = Reverse (slow); while (right) { if (left->val != right->val) return false ; left = left->next; right = right->next; } return true ; } };