题目描述
算法分析
方法一:可以利用树的后序遍历思维来做
但是压栈使得空间复杂度为O(n),由于比较了半个链表的长度,时间复杂度为O(n)
思路:
1、两个辅助指针 left 和 right,其中left 指向头结点后不动, right后序遍历出栈和left作比较
细节:
1、为什么right==nullptr时返回的true,这里的base case其实就是当输入结点为空,就是回文链表。
2、left = left->next,这是因为right为空时返回到上一层,与left做完比较后继续返回,left需要像右移动
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* left;
bool isPalindrome(ListNode* head) {
left = head;
return treverse(head);
}
bool treverse(ListNode* right)
{
if(right == nullptr) return true;
bool res = treverse(right->next);
//后序遍历
res = res && (left->val == right->val);
left = left->next;
return res;
}
};
方法二:使用迭代反转链表的思想
思路:
1、首先构造一个可以反转位置n之后结点的辅助函数
2、通过双指针法找到原链表的中间位置
3、将中间位置之后的部分反转并且让头部有指针接住
4、前后两个指针比较,然后向后移动,直到为空,退出函数
细节:
可画图理解,奇数个中间那个值不用比较,因为一个元素的数据结构本身就是回文,所以right向右移动一步
//2、假如fast不为空,说明为奇数个长度
if (fast != nullptr)
{
slow = slow->next;
}
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
//反转链表
ListNode* reverse(ListNode* pos)
{
ListNode *pre, *cur, *nxt;
cur = nxt = pos;
pre = nullptr;
while (cur != nullptr)
{
nxt = cur->next;
cur-> next = pre;
pre = cur;
cur = nxt;
}
//因为cur==nullptr退出,所以返回pre
return pre;
}
bool isPalindrome(ListNode* head) {
//1、先通过「双指针技巧」中的快慢指针来找到链表的中点:
ListNode* left, *right, *fast, *slow;
fast = slow = head;
while (fast != nullptr && fast->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
//2、假如fast不为空,说明为奇数个长度
if (fast != nullptr)
{
slow = slow->next;
}
//3、从slow开始反转后面的链表,现在就可以开始比较回文串了:
left = head;
right = reverse(slow);
while (right != nullptr)
{
if (right->val != left->val) return false;
right = right->next;
left = left->next;
}
return true;
}
};