题目描述:
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
示例:
1->2->2->1
返回:true
思路分析:
回文结构即是链表关于中心节点对称,如果没有复杂度要求,可以暴力解法将链表转移到数组中进行判断,或者利用前面博客中讲的尾插的思路来反转链表(传送门:(53条消息) 详解反转链表的思路及方法_好运轩的博客-CSDN博客),一一进行对照。既然无法重新创建新的链表,那么可以反转链表的后半段,然后再对照前后半段链表是否满足回文结构。
在这个思路下,首先要寻找链表的中间节点(节点数为奇数情况下),或者是中间节点的后一个节点(节点数为偶数情况下),可以利用前面的博客来完成此步骤(传送门:(53条消息) 快慢指针找单链表的中间节点(有复杂度的限制)_好运轩的博客-CSDN博客)。其次在反转后半部分链表。最后进行比较。
注意:
如果节点数为奇数的情况下,会出现前半段反转后的链表(n/2 -1)的节点数小于后半段链表的节点数(n/2 +1),那么该如何判断是否满足回文结构呢?
这种思路刚好解决的这种情况,虽然后半段链表反转了,但前半段链表的最后一个节点的指针域仍然指向那个原来的中间节点,如图所示:
![](https://img-blog.csdnimg.cn/img_convert/7896f8a0925b2708dd4170b2aa229526.png)
因此,不需要单独判断该问题
代码实现:
bool chkPalindrome(ListNode* A) {
//write code here
寻找中间节点
struct ListNode* fast,* slow;
fast = slow = A;
while(fast&& fast->next)
{
slow = slow->next;
fast = fast ->next ->next;
}
struct ListNode* mid = slow;
//翻转后半部分链表
struct ListNode* cur = mid;
struct ListNode* newHead = NULL;
while(cur)
{
struct ListNode* next =cur ->next;
cur ->next = newHead;
newHead = cur;
cur = next;
}
//判断前半部分链表和后半部分链表是否相同
while(newHead && A)
{
if(newHead ->val != A ->val)
return false;
else
{
newHead = newHead ->next;
A = A ->next;
}
}
return true;
}