2022-09-05 22:40阅读: 29评论: 0推荐: 0

力扣-234-回文链表

这只是一道简单题,我看到题目示例的时候理所当然地想用“栈”来解决

扫描一个元素,如果栈空或者栈顶元素不等于当前节点值,就压栈,否则弹栈
后来却接连碰壁

  1. 没有考虑单节点,例如“1”地情况
  2. 没有考虑单数节点,例如“101”地情况
    其实本质上还是没有考虑单数的情况
    栈其实不好解决单数的情况,还是因为不知道长度的原因

我找到一个老哥写的栈解法
其实是这样:

  1. 遍历一遍链表,并把每个元素入栈
  2. 再遍历一遍链表,把每个元素和栈顶元素比较(比一个弹一个)
    如果有不一样的,就返回false,否则返回true

O(N)的空间复杂度(一个长度为n的栈),其实还可以遍历一遍放入一个数组,然后首尾双指针往中间靠并比较元素是否相同,也差不多的

其实在做的过程中也意识到了,这并不是最优的做法,题目提示时间O(N),空间O(1)
其实应该用双指针……但是这是个链表啊,我不知道它的长度,就没法两头往中间扫描

O(1)空间复杂度用指针的解法肯定是跑不掉的,而且肯定是同向指针,只是我没想出来

官方题解

官方的题解是快慢指针:找到中间节点,然后反转后半部分的节点
这里复习一下反转反转链表我记得最好的解法是用复制节点来做(记混了)

这里有一个我没想起来的点——通过快慢指针找链表的中间节点

快、慢指针初始位置都在链表头,快指针一次走两步,慢指针一次走一步,当快指针走到链表尾部的时候,慢指针指向的就是中间节点

思路

思路是这样的:

  1. 先找到链表的中间节点,用快慢指针的方法

如果是复数节点,就是前半部分的最后一个

  1. 将后半部分指针链表反转,返回尾节点的指针
  2. 头尾两个指针向中间靠,如果指向的值不一致,就表示不是回文链表

官方题解里有额外的操作,定义了一个布尔值,主要是为了后面把反转的后半部分链表再恢复过来

class Solution {
public:
// 找中间节点
ListNode* endOfHalfStart(ListNode* head) {
ListNode* fast = head;
ListNode* slow=head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
}
bool isPalindrome(ListNode* head) {
if (!head) return true;
// 找到中间节点(前半部分的尾节点)并反转后半部分节点
ListNode* firstHalfEnd = endOfHalfStart(head);
// 这应该是尾节点才对吧
ListNode* secondHalfStart = reverseList(firstHalfEnd->next);
// 双指针,一个指向头,一个指向尾
ListNode* p1 = head;
ListNode* p2 = secondHalfStart;
bool result = true;
// 为什么这里p2的条件是!=nullptr,而不是!=p1
// 因为反转后中间节点(后半部分的第一个节点)的next指向会被置空 nullptr,这个节点被前后两个节点指向
// 这个情况在单双都会发生
while (result && p2 != nullptr) {
if (p1->val != p2->val) result = false;
p1 = p1->next;
p2 = p2->next;
}
firstHalfEnd->next = reverseList(secondHalfStart);
return result;
}
ListNode* reverseList(ListNode* head) {
ListNode* pre= nullptr;
ListNode* cur = head;
while (cur) {
ListNode* nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
};

这边还有道兄弟题:力扣-9-回文数

本文作者:YaosGHC

本文链接:https://www.cnblogs.com/yaocy/p/16659234.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(29)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起