题目描述
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
题解
思路一:数组
使用数组存储链表中的元素,用两个指针从首尾遍历判断
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (head == NULL) return true;
ListNode* temp = head;
//设置一个哨兵,存储最终结果
bool flag = 1;
int n = 0,i = 0;
//获取链表长度
while(temp != NULL){
temp = temp->next;
n++;
}
temp = head;
int* p = new int[n];
//将链表中节点的值放入数组
while(temp != NULL){
p[i++] = temp->val;
temp = temp->next;
}
n = 0;
//判断是否为回文链表
//当头部指针 < 尾部指针时,所有判断完成
while(i >= n){
if(p[n++] != p[--i] ) flag = 0;
}
delete[] p;
return flag;
}
};
思路二:递归
递归结束条件:head->next ==NULL
使用两个指针*p,*q 判断前后两个回文位置是否相等
p指向头部
q指向当前遍历的节点
q节点每次往前移动一次,p = p->next
p从前往后遍历全部节点,q从后往前遍历全部节点
只要发现一次p->val != q->val 接下来一直返回false
若是回文节点 一直返回true
class Solution {
public:
//默认为回文链表,返回值为true
bool flag = 1;
//哨兵:判断是否为头结点
int f1=0;
//头部指针
ListNode *p = NULL;
bool isPalindrome(ListNode* head) {
//判断是否为头节点,让p指向头结点
if( f1 == 0){
f1++;
p = head;
}
// 递归终止条件 or 判断是否为空
if(head == NULL) return true;
//让q指向当前遍历节点,q会从尾部开始使用
ListNode* q=head;
//递归开始
flag = isPalindrome(head->next);
//已经判断过的节点全为回文节点对,则继续判断
if(flag) {
//非回文节点
if(p->val != q->val) {
p = p->next;
return false;
}
//回文节点
else if(p->val == q->val){
p = p->next;
return true;
}
}
//一旦出现非回文节点,不再判断,直接返回false
else if (!flag )return flag;
return flag;
}
};
思路三:栈
用栈顺序存储链表中的节点,利用栈先进后出的特性判断每对回文节点
class Solution {
public:
bool isPalindrome(ListNode* head) {
stack<int> s;
ListNode* p = head;
while(p){
s.push(p->val);
p = p->next;
}
while(head){
if(head->val != s.top())
return 0;
s.pop();
head = head->next;
}
return 1;
}
};
思路四:反转链表
一、快慢指针:翻转后半部分
使用快慢指针,快指针一次走两个节点,慢指针一次走一个,当快指针走到尾部,慢指针走到了中间。
翻转后半部分的链表,翻转链表题目已经写过,详情点击链接:
Leetcode链表206. 反转链表
然后依次比较即可
若是奇数个节点,前后两个链表全都指向中间节点
若为偶数个节点,前后链表最后两个节点是对称的
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head == NULL || head->next == NULL)
return true;
ListNode* q = head;
ListNode* s = head;
while(q && q->next){
q = q->next->next;
s = s->next;
}
s = reverseList(s);
while(s){
if(head->val != s->val)
return false;
s = s->next;
head = head->next;
}
return true;
}
ListNode* reverseList(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;
while (cur != NULL){
ListNode* temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
二、快慢指针:翻转前半部分
慢指针边走边翻转
思路差不多,就是把翻转代码直接放到第一次while循环里面,不想写了,就直接从LeetCode上面扣下来的
class Solution {
public:
bool isPalindrome(ListNode* head) {
//无节点
if(!head)
return true;
//一个节点
if(!head->next)
return true;
bool res = 1;
ListNode* fast = head;
ListNode* slow = head;
ListNode* reverse = head;
ListNode* reverse_pre = NULL;
ListNode* start;
while(fast->next && fast->next->next){
fast = fast->next->next;
reverse = slow;
slow = slow->next;
reverse->next = reverse_pre;
reverse_pre = reverse;
}
//判断是否为节点数>2的偶数个节点,将最后一个节点接在头部
if(fast->next &&fast!=head){
start = slow->next;
slow->next = reverse;
reverse = slow;}
//奇数个节点或者只有两个节点的情况
else
start = slow->next;
while(start && reverse){
if(start->val != reverse->val)
res = 0;
start = start->next;
reverse = reverse->next;
}
return res;
}
};