力扣-234-回文链表
这只是一道简单题,我看到题目示例的时候理所当然地想用“栈”来解决
扫描一个元素,如果栈空或者栈顶元素不等于当前节点值,就压栈,否则弹栈
后来却接连碰壁
- 没有考虑单节点,例如“1”地情况
- 没有考虑单数节点,例如“101”地情况
其实本质上还是没有考虑单数的情况
栈其实不好解决单数的情况,还是因为不知道长度的原因
我找到一个老哥写的栈解法
其实是这样:
- 遍历一遍链表,并把每个元素入栈
- 再遍历一遍链表,把每个元素和栈顶元素比较(比一个弹一个)
如果有不一样的,就返回false,否则返回true
O(N)的空间复杂度(一个长度为n的栈),其实还可以遍历一遍放入一个数组,然后首尾双指针往中间靠并比较元素是否相同,也差不多的
其实在做的过程中也意识到了,这并不是最优的做法,题目提示时间O(N),空间O(1)
其实应该用双指针……但是这是个链表啊,我不知道它的长度,就没法两头往中间扫描
O(1)空间复杂度用指针的解法肯定是跑不掉的,而且肯定是同向指针,只是我没想出来
官方题解
官方的题解是快慢指针:找到中间节点,然后反转后半部分的节点
这里复习一下反转反转链表,我记得最好的解法是用复制节点来做(记混了)
这里有一个我没想起来的点——通过快慢指针找链表的中间节点
快、慢指针初始位置都在链表头,快指针一次走两步,慢指针一次走一步,当快指针走到链表尾部的时候,慢指针指向的就是中间节点
思路
思路是这样的:
- 先找到链表的中间节点,用快慢指针的方法
如果是复数节点,就是前半部分的最后一个
- 将后半部分指针链表反转,返回尾节点的指针
- 头尾两个指针向中间靠,如果指向的值不一致,就表示不是回文链表
官方题解里有额外的操作,定义了一个布尔值,主要是为了后面把反转的后半部分链表再恢复过来
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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步