题目要求:
现给定一个链表ListNode* pHead,定义bool代表链表是否为回文,请编写程序。
测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false
思想:
本题的思路分为三步走:
找寻中间位置->将链表分为两部分,对后一部分进行翻转->进行指针指向数据的比较。
1、找寻中间位置
找寻中间位置,还是运用快慢指针的思想,(具体细节参考我的之前有一篇博客快慢指针的两道题目,里面有详细的讲解)。在对于单链表的操作之中,快慢指针的思想能够帮助我们解决绝大多数部分的问题。
2、将链表分为两部分,对后一部分进行翻转
举个例子:1->2->3->2->1
进行第一步之后,我们得到中间元素对应的val值为3,此时我们定义一个结构体指针变量slow指向此处,此时在定义一个结构体变量为prev,指向slow指向元素的前一个元素,即val值为2的地址。此时找到之后,将prev->next = NULL。
即1->2与3->2->1这两个链表。
得到这两个链表之后,对3->2->1进行翻转。
翻转的思想还是要根据以下的代码去自己手动画图实现一下,加深对这个过程的理解。
翻转完成后,一定要将slow置为reverseHead指向的地址。
3、进行指针指向的val的比较
**特别注意:**循环体进行的条件一定要为原链表pHead指向的元素完后走不为空的情况下进行。
例如,得到1->2与3->2->1这两个链表,pHead指向的地址是1->2中val=1对应的结构体地址,slow指向的地址是3->2->1中val=3对应的结构体地址。此时如果用slow是否为空去判断会造成栈溢出的报错,因此要使用pHead是否为空去判定。
代码实现:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Palindrome {
public:
bool isPalindrome(ListNode* pHead) {
// write code here
if(pHead == NULL)
{
return false;
}
ListNode* fast = pHead;
ListNode* slow = pHead;
ListNode* prev = pHead;
ListNode* reverseHead = NULL;
//1、运用快慢指针找到链表的中间元素
//若链表元素个数为奇数,则找寻中间元素
//若链表元素个数为偶数,找出中间元素靠后的那一个元素
while(fast && fast->next)
{
fast = fast->next->next;
prev = slow;
slow = slow->next;
}
//slow指向链表中间元素后,将其前一位链表元素对应的next置为空,变成两个链表
prev->next = NULL;
//2、从找到的中间位置对其之后的链表元素进行翻转。
while(slow)
{
ListNode* next = slow->next;
slow->next = reverseHead;
reverseHead = slow;
slow = next;
}
//将翻转之前的slow之前一位的个数置为翻转之后slow指向的位置
slow = reverseHead;
//3、比较
while(pHead)
{
if(pHead->val != slow->val)
{
return false;
}
else
{
pHead = pHead->next;
slow = slow->next;
}
}
return true;
}