思路:我们把链表看成前半部分和后半部分,把后半部分翻转和前半部分对比,看是否是回文链表。这里用c语言写的。
步骤:
1.找到后半部分的链表表头:快慢指针做法,快指针一次走两步,慢指针一次走一步,快指针不能再继续走的时候慢指针正好走到中点。
2.翻转后半部分链表
3.对比前半部分
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
if(head==NULL || head->next==NULL) return head;
struct ListNode* pnewhead=NULL;
struct ListNode* ptake=head;
struct ListNode* pbroke=head->next;
while(1)
{
ptake->next=pnewhead;
if(pbroke==NULL) return ptake;
pnewhead=ptake;
ptake=pbroke;
pbroke=pbroke->next;
}
}
struct ListNode* ListHalf(struct ListNode* head) {
struct ListNode* fast=head;
struct ListNode* slow=head;
while(fast->next && fast->next->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
bool isPalindrome(struct ListNode* head) {
if(head==NULL)
return true;
struct ListNode* head2=ListHalf(head);
head2=reverseList(head2->next);
bool res=true;
while(res && head2)
{
if(head->val!=head2->val) return false;
head2=head2->next;
head=head->next;
}
return res;
}
思路:在区间[left,right]翻转链表,然后再拼接上。
步骤:
1.需要四个位置的节点,left的前一个结点,left节点,right节点,right的后一个节点。
2.翻转[left,right]。
3.重新连接,left前一个结点连right节点,left节点连right后一个节点。
(注:由于考虑到表头翻转之后改变这个情况,引入虚拟头节点Head。)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
#include<stdio.h>
void reverseList(struct ListNode* head) {
struct ListNode* pnewhead=NULL;
struct ListNode* ptake=head;
struct ListNode* pbroke=head->next;
while(1)
{
ptake->next=pnewhead;
if(pbroke==NULL) break;
pnewhead=ptake;
ptake=pbroke;
pbroke=pbroke->next;
}
}
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
int len=0;
struct ListNode* Head=malloc(sizeof(struct ListNode));
Head->val=-1;
Head->next=head;
//left的前一个结点
struct ListNode* leftlinkheadpre=Head;
while(len!=left-1)
{
leftlinkheadpre=leftlinkheadpre->next;
len++;
}
//right节点
struct ListNode* rightlinkend=leftlinkheadpre;
while(len!=right)
{
len++;
rightlinkend=rightlinkend->next;
}
//left节点
struct ListNode* leftlinkhead=leftlinkheadpre->next;
//right后一个节点
struct ListNode* rightlinkhend=rightlinkend->next;
leftlinkhead->next==NULL;
rightlinkend->next=NULL;
reverseList(leftlinkhead);
leftlinkheadpre->next=rightlinkend;
leftlinkhead->next= rightlinkhend;
return Head->next;
}
这种方法在left是头节点,right是尾节点时,会遍历两次链表,那么还有一种头插法方式,可以遍历一次。
思路:在需要反转的区间里,每遍历到一个新的节点,就把新节点插到前面去,举个例子,蓝色是需要翻转的区间。
1->2->3->4->5->6 => 1->2->4->3->5->6 => 1->2->5->4->3->6
定义left的前一个节点preleft,向后移动的节点back,向前移动的节点front。
perleft不动然后按照(1)(2)(3)顺序移动
back->next=front->next; front->next=preleft->next; leftpre->next=front;
(其实back一直指向3)back一直不动,front=back->next; 然后继续执行这三步 back->next=front->next; front->next=preleft->next; leftpre->next=front;
最后变成这样
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
int len=0;
struct ListNode* Head=malloc(sizeof(struct ListNode));
Head->val=-1;
Head->next=head;
//left的前一个结点
struct ListNode* leftpre=Head;
while(len!=left-1)
{
leftpre=leftpre->next;
len++;
}
//back节点
struct ListNode* back=leftpre->next;
//front节点
struct ListNode* front=NULL;
while(len!=right-1)
{
len++;
front=back->next;
back->next=front->next;
front->next=leftpre->next;
leftpre->next=front;
}
return Head->next;
}