问题描述
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
提示:
- 链表中节点数目在范围
[1, 105]
内 0 <= Node.val <= 9
进阶:你能否用 O(n)
时间复杂度和 O(1)
空间复杂度解决此题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
快慢指针
首先我并不认为这是一个简单题。。。。。那我来说一下我的思路吧:
题目要求了空间复杂度和时间复杂度,这就比较难搞了。所以我们只能扫描一遍,并且要使用常数级的空间。
我们通过快慢指针来对这个链表分成两段,慢指针每次走一步,快指针每次走两步,当快指针为空时,慢指针恰好走到了链表的中间,那么就可以把这个链表分成两段了。当然在这个过程注意一下链表长度是奇数还是偶数,处理稍有不同。如果此时直接比较,由于两段链表的元素顺序是相反的,所以还是不行。因此我们在分段时就通过slow
把前半段链表倒置。链表倒置还是比较简单的吧,前面也遇到过。一般都是设置一个哑结点,只不过这里这样总是报奇奇怪怪的错误:heap-use-after-free
,实在是不知道为啥。后来我想了想,若通过设置哑结点来倒置,那么倒置完成的最后一个结点的next
值是指向自身的。。。(当然我把这个改正了还是会报错)。这里提供一个新的思路,哑结点我们不是new出来了,而是一开始为nullptr
,当第一个结点出现时赋值就行,以后每次都被赋值为第一个结点就好了。。具体可以看下面的代码了。
代码:
//判断一个链表是否是回文链表
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return true;
}
ListNode* dumb = nullptr;
ListNode* slow = head;
ListNode* fast = head;
ListNode* pre = nullptr;
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next;
fast = fast->next;
pre = slow;
slow = slow->next;
pre->next = dumb;
dumb = pre;
}
if (fast == nullptr) {//长度为偶数,slow指向后半截第一个元素,pre指向前半截最后一个元素
fast = slow;
slow = dumb;
}
else if (fast->next == nullptr) {//长度为奇数,slow指向中间的元素
fast = slow->next;
slow = dumb;
}
while (fast != nullptr) {
if (fast->val != slow->val) {
return false;
}
slow = slow->next;
fast = fast->next;
}
return true;
}
};
执行结果: