反转的整体思想是:每遍历到一个节点后,让该节点来到反转部分的起始位置。
这个过程像是头插法。
ListNode *reverseBetween1(ListNode *head,int left,int right)
{
ListNode *pre=NULL;
ListNode *ans=(ListNode *)malloc(sizeof(ListNode));
ans->next=head;
pre=ans;
for(int i=0;i{
pre=pre->next;
}
ListNode *cur=pre->next;
ListNode *next=NULL;
for(int i=0;i{
next=cur->next;
cur->next=next->next;
next->next=pre->next;
pre->next=next;
}
ListNode *NewHead=ans->next;
free(ans);
return NewHead;
}
先确定好需要反转的部分,然后将链表分成3部分,将要反转的部分拿出来,反转后放入正确的位置。
ListNode *reverseBetween2(ListNode *head,int left,int right)//穿针引线法先把left和right之间的部分翻转再接上
{
ListNode *dummyNode=(ListNode *)malloc(sizeof(ListNode));
dummyNode->next=head;
ListNode *pre=dummyNode;
for(int i=0;i{
pre=pre->next;
}
ListNode *leftNode=pre->next;
ListNode *rightNode=pre;
for(int i=0;i{
rightNode=rightNode->next;
}
ListNode *succ=rightNode->next;
pre->next=NULL;
rightNode->next=NULL;
ListNode *NewLeftNode=reverseList(leftNode);
if(rightNode==NewLeftNode)
cout<<"1"<else
cout<<"0"<leftNode->next=succ;
//pre->next=NewLeftNode;//T
pre->next=rightNode;//T
ListNode *NewHead=dummyNode->next;
free(dummyNode);
return NewHead;
}ListNode *reverseList(ListNode *head)//不建立虚拟头节点的翻转链表,可以背诵
{
ListNode *pre=NULL;
ListNode *cur=head;
while(cur!=NULL)
{
ListNode *next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
return pre;
}
LeetCode 24
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3]示例 2:
输入:head = [] 输出:[]示例 3:
输入:head = [1] 输出:[1]
题目的意思是:如果原始顺序为dummyNode->node1->node2,我们需要把他变成 dummyNode->node2->node1。
ListNode *SwapPairs(ListNode *head)
{
ListNode *temp=NULL;
ListNode *dummyNode=(ListNode *)malloc(sizeof(ListNode));
dummyNode->next=head;
temp=dummyNode;
while(temp->next!=NULL&&temp->next->next!=NULL)
{
ListNode *node1=temp->next;
ListNode *node2=temp->next->next;
node1->next=node2->next;
node2->next=node1;
temp->next=node2;
temp=node1;
}
ListNode *NewHead=dummyNode->next;
free(dummyNode);
return NewHead;
}
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例1:
输入:l1 = [7,2,4,3], l2 = [5,6,4] 输出:[7,8,0,7]示例2:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[8,0,7]示例3:
输入:l1 = [0], l2 = [0] 输出:[0]
加法是从最低位开始,但链表的遍历从最高位开始。先把链表反转,从低位开始遍历。链表反转可以新建一个链表,也可以用原链表反转。然后用尾插法新建一个链表,从低位开始把节点插入链表。
ListNode *addTwoNumbers(ListNode *l1,ListNode *l2)
{
ListNode *st1=NULL;
ListNode *st2=NULL;
ListNode *curr1=l1;
ListNode *curr2=l2;
while(curr1!=NULL)//st1在这里是第一个链表反转后的头节点
{
ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
new_Node->val=curr1->val;
new_Node->next=st1;
st1=new_Node;
curr1=curr1->next;
}
while(curr2!=NULL)//st2在这里是第二个链表反转后的头节点
{
ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
new_Node->val=curr2->val;
new_Node->next=st2;
st2=new_Node;
curr2=curr2->next;
}
curr1=st1;
curr2=st2;
int suma=0,sumb=0;
ListNode *new_head=(ListNode *)malloc(sizeof(ListNode));//要返回的新链表的头节点
new_head->val=-1;
new_head->next=NULL;
int carry=0;
while(curr1!=NULL||curr2!=NULL||carry!=0)
{
ListNode *new_Node=(ListNode *)malloc(sizeof(ListNode));
if(curr1!=NULL)
{
suma=curr1->val;
curr1=curr1->next;
}
else
{
suma=0;
}
if(curr2!=NULL)
{
sumb=curr2->val;
curr2=curr2->next;
}
else
{
sumb=0;
}
int get_sum=suma+sumb+carry;
int ans=get_sum%10;//ans是要存入新链表的数据
int carry=get_sum/10;//carry是进位
new_Node->val=ans;
new_Node->next=new_head->next;
new_head->next=new_Node;
}
ListNode *ret=new_head->next;
free(new_head);
return ret;
判断链表回文。先反转一半链表,会将原链表分成两段新的链表(如果是偶数个节点,会分成两段链表。如果是奇数个节点,会分成3段。中间部分只是一个节点)。 分别从头遍历两段链表,只要有一次节点的数据域不相等,返回false。如果都遍历完成,则返回true。
bool isPalindrome(ListNode *head)
{
if(head==NULL&&head->next==NULL)
{
return true;
}
ListNode *fast=head;
ListNode *slow=head;
ListNode *pre=head;
ListNode *prepre=NULL;
while(fast!=NULL&&fast->next!=NULL)//将一半链表反转
{
pre=slow;
slow=slow->next;
fast=fast->next->next;
pre->next=prepre;
prepre=pre;
}
if(fast!=NULL)//提示是奇数个节点的链表,slow移动至中间节点的下一个节点
{
slow=slow->next;
}//pre和slow分别是两段链表的头节点
while(pre!=NULL&&slow!=NULL)
{
if(pre->val!=slow->val)
return false;
pre=pre->next;
slow=slow->next;
}
return true;
}