题目描述:
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
解题思路:解这道题分三步!
第一步:找到这个链表的中间节点
第二步:将这个中间节点之后(包括这个中间节点)的全部节点进行反转
第三步:定义一个指针指向链表的头,一个指针指向反转后的中间节点,进行比较,若有一个值不同,则return false,若一直比较,直到指向反转后的中间节点的指针为空或者这个指针的下一个节点为空,即return true。
具体解法如下:
第一步:使用双指针来找链表的中间节点。
定义slow和fast两个指针,开始时两个指针都指向头节点,然后规定slow每次走一步,fast每次走两步,即slow = slow->next; fast = fast->next->next; 结束循环的条件是fast!=NULL或者是fast->next!=NULL,这得看链表的长度是多少,若链表的长度n==偶数,那么则是第一种结束条件,若n==奇数,那么则是第二种结束条件。
代码如下:
struct ListNode*slow=head;
struct ListNode* fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast = fast->next->next;
}
struct ListNode* mid = slow; //定义指针mid来记录这个中间节点
第二步:反转中间的链表
定义一个指针newnode指向NULL,作为反转后尾节点所指向的空指针。然后从mid开始,让mid指向newnode,让mid成为反转后链表的尾节点,然后定义指针next指向mid->next,以此来记录剩余的链表节点,防止出现野指针。循环结束的条件为mid==NULL。
代码如下:
struct ListNode* newnode = NULL;
struct ListNode* next = NULL;
while(mid)
{
next=mid->next;
mid->next=newnode;
newnode = mid;
mid = next;
}
struct ListNode* rmid = newnode;//定义指针rmid来记录反转后的中间节点。
第三步:比较,判断
第二步中,反转以后有一个很妙的细节。
比如,如果给的原始链表为1 2 3 2 1,那么反转后,就成了1 2 1 2 3,那么此时,第一个2的下一个节点依然指向了3,并没有指向了它后面的1,所以,在判断的时候,可以完全放心大胆地判断值是否相等,不相等的,就不是回文结构了。
定义指针cur来指向头节点,判断cur->val 是否与 rmid->val 相等,若不是,直接return false; 若是,迭代往下判断:cur = cur->next; rmid =rmid->next; 循环结束的条件为rmid==NULL;
代码如下:
struct ListNode* cur = head;
while(rmid)
{
if(cur->val!=rmid->val)
{
return false;
}
cur = cur->next;
rmid = rmid->next;
}
return true;
}
因此,这道题的完整解题思路如上文所述。