力扣-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-回文数

posted @ 2022-09-05 22:40  YaosGHC  阅读(40)  评论(0)    收藏  举报