面试题 02.06. 回文链表 试试这题
编写一个函数,检查输入的链表是否是回文的
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
思路:首先要得到链表的一半,然后将前半部分或后半部分的链表逆置,然后和前面的另一半比对,若相同则是回文的,反之则不是,细节请看代码
第一种方法:找中间结点+头插逆置
先求出结点总个数然后即可以找到中间位置,这样效率不高,但是可以把链表的结构掌握的很清楚
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode Node;
bool isPalindrome(struct ListNode* head){
Node* cur = head;
int cnt = 0;
while(cur)
{
cur = cur->next;
cnt++;
}
cur = head;//记得要将cur在返回head结点
int jud = cnt % 2;//判断结点的个数是奇数还是偶数
//定义一个number保留中间结点的位置
int number = cnt = cnt / 2;
while(number--)
{
cur = cur->next;
}
if(jud == 1)
cur = cur->next;//如果是奇数个结点,那么就跳过中间结点
//开始头插逆置
Node* newhead = NULL;
while(cnt--)
{
Node* next = cur->next;
cur->next = newhead;
newhead = cur;
cur = next;
}
while(newhead && head)
{
if(head->val != newhead->val)
return false;
newhead = newhead->next;
head = head->next;
}
return true;
}
第二种方法:双指针+头插逆序
利用fast指针和slpw指针,fast指针每次做两步,slow指针每次走一步,然后两个指针同时遍历链表,当fast指针走完链表的时候,这时slow指针只走了链表的一半,这就是上面的优化,后面的头插比对有一点点不一样,我会在代码中提示出来。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode Node;
bool isPalindrome(struct ListNode* head){
if(head == NULL || head->next == NULL)
return true;
Node* fast = head;
Node* slow = head;
Node* prev = head;//保留链表的中间结点的上一个结点,为了让两个链表分开
//因为节点数可能是奇数可能是偶数,所以要用fast(偶数)fast->next(奇数)判断
while(fast && fast->next)
{
prev = slow;
fast = fast->next->next;
slow = slow->next;
}
//将前半部分链表和后半部分分开,易错点
prev->next = NULL;
//头插后半段的链表
Node* newhead = NULL;
while(slow)
{
Node* next = slow->next;
slow->next = newhead;
newhead = slow;
slow = next;
}
//比对两个链表,但是要注意如果节点数是奇数的话,两个链表的节点数不相同,所以判断的时候要以,前半部分的结束为结束
while(head)
{
if(head->val != newhead->val)
return false;
head = head->next;
newhead = newhead->next;
}
return true;
}