Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
给定一个链表的 头节点 head , 请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1:
输入: head = [1,2,3,3,2,1] 输出: true
示例 2:
输入: head = [1,2] 输出: false
提示:
链表 L 的长度范围为 [1, 105] 0 <= node.val <= 9
进阶:能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路
该题是一道简单题,比较考察人的思维能力。我们可以很容易想到多种解决方案,可以先遍历链表,把链表中所有的值都存入一个数组中,然后利用栈的数据结构进行优化,先把一半的元素入栈,然后挨个出栈与数组中后面的元素进行比较,不相同则返回fasle,如果栈为空,说明这个数组是回文数组即返回true。
这样做的空间复杂度很高,我们可以利用双指针算法进行优化,用一个指针指向数组的开头,另一个指针指向数组的结尾,两个指针互相靠近直到相遇,如果出现两指针值不同,则返回false。这样利用指针替代了栈,可以降低空间复杂度。
代码
使用栈
/**
* 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* p = head;
vector<int> ans;
stack<int> s1;
int j = 0;
while(p != nullptr)
{
ans.push_back(p -> val);
p = p -> next;
j ++;
}
//for(int i = 0;i < j;i ++) cout << ans[i];
int length = ans.size();
int aa = 0;
if(length % 2 == 0) aa = length / 2;
else aa = length / 2 + 1;
for(int i = 0;i < length / 2; i++)
{
s1.push(ans[i]);
}
while(!s1.empty() && aa < length)
{
if(s1.top() != ans[aa ++]) break;
s1.pop();
}
return s1.empty();
}
};
使用双指针
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* p = head;
vector<int> ans;
stack<int> s1;
int j = 0;
while(p != nullptr)
{
ans.push_back(p -> val);
p = p -> next;
j ++;
}
//for(int i = 0;i < j;i ++) cout << ans[i];
int length = ans.size();
// 双指针
for(int i = 0 ,j = length - 1;i < j;i ++ ,j --)
{
if(ans[i] != ans[j]) return false;
}
return true;
}
};
总结
遇到判断回文串时,可以使用双指针算法求解。