题目
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
进阶:你能否用 O(n)
时间复杂度和 O(1)
空间复杂度解决此题?
解法1
如果要比较是否为回文链表,可将链表中的数据保存至一个vector容器中,然后将链表由头到尾,vector容器由尾到头,逐一对值进行比较。如果值完全一致,则为回文链表,否则不为回文链表。
代码如下:
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> buffer{};
ListNode* tmp = head;
while (tmp != nullptr) {
buffer.push_back(tmp->val);
tmp = tmp->next;
}
int size = buffer.size();
for (int i = size - 1; i >= size / 2; --i) {
if (buffer[i] != head->val) {
return false;
}
head = head->next;
}
return true;
}
};
时间复杂度为O(n),空间复杂度为O(n)。执行结果如下:
解法2:递归法
可以通过递归遍历至节点的尾部,这样出栈的时候就可以逆序访问链表节点了。在类的内部保存一个节点存储链表的头指针,而递归遍历至节点尾部后就可以逆序遍历链表节点。如果两个值一致,将继续递归出栈,而当前的节点往后移动。如果两个值不一致,则不进行比较,直接返回false,表示为非回文链表。
代码如下:
class Solution {
public:
bool isPalindrome(ListNode* head) {
curHead_ = head;
return check(head);
}
private:
bool check(ListNode* node) {
if (node == nullptr) {
return true;
}
// 前一次比较结果为true,才进行本次比较处理,否则直接返回false
if (!check(node->next)) {
return false;
}
// 前后两个节点的值不一致,直接返回false
if (node->val != curHead_->val) {
return false;
}
curHead_ = curHead_->next;
return true;
}
private:
ListNode* curHead_{nullptr};
};
时间复杂度为O(n),空间复杂度为O(1)。执行结果如下:
解法3:快慢指针
分别定义一个快指针和慢指针,快指针每次走两步,慢指针每次走一步,这样快指针遍历到尾部后,慢指针到链表的中间节点,并且慢指针在前进的过程反转链表,这样就可以从中间向两边开始遍历,从而判断链表是否为回文链表。
代码如下:
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
// 找到链表中点
while ((fast != nullptr) && (fast->next != nullptr)) {
fast = fast->next->next;
slow = slow->next;
}
// 反转链表前半部分
ListNode* pre = nullptr;
ListNode* cur = head;
while (cur != slow) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
// 前半部分链表逆序后的头节点
ListNode* left = pre;
// 后半部分链表的头节点,和链表的节点个数的奇偶有关系
ListNode* right = (fast == nullptr) ? slow : slow->next;
while ((left != nullptr) && (right != nullptr)) {
if (left->val != right->val) {
return false;
}
left = left->next;
right = right->next;
}
return true;
}
};
时间复杂度为O(n),空间复杂度为O(1)。执行结果如下: