[234. 回文链表]
「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。
题目描述
给你一个单链表的头节点 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)空间复杂度解决此题?
思路
在判断回文的时候,在字符串中,一般都是从头和从尾开始一一比较,但是链表不支持从后面开始遍历,所以这个办法不行,但是也可使用额外的空间,将链表转化数组,按上述办法比较。回文有一个性质,就是翻转之后与未翻转时一致,所以我们可以新建一条链表为原链表的翻转,之后进行比较。为了满足进阶的要求,其实我们可以只在原地翻转链表的前半部分,再将前后两部分进行比较即可。找到前半部分可以用速度不同的双指针,翻转链表也是使用双指针,之前的题目已经有过应用。
代码实现
第一个while循环,fast是在辅助找中间的节点。slow节点最后会指向中间节点,并且也在进行翻转的工作。之后在另一个while循环进行比较即可得出结果。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* pre = nullptr;
ListNode* slow = head;
ListNode* fast = head;
while(fast!=nullptr && fast->next!=nullptr){ //找中间节点
fast=fast->next->next; //二倍速找到中间节点
ListNode* temp=slow->next; //翻转slow节点
slow->next=pre;
pre=slow;
slow=temp;
}
if(fast!=nullptr) slow=slow->next; //如果节点数为奇数,那么需要跳过最中间节点,开始比较
while(slow!=nullptr){ //比较
if(slow->val!=pre->val) return false;
slow=slow->next;
pre=pre->next;
}
return true;
}
};
总结
在链表上使用双指针,在速度,起点进行了综合考虑。