题目:
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
思路:
类似于这种链表题,其实很好的一个习惯要先自己在纸上模拟过程,对于写代码有很好的思路指引过程。做过反转全部链表的小伙伴应该有印象,反转全部链表我们的办法,可以用到双指针迭代,可以用递归。举一反三我们这里反转局部链表呢。再用递归的话是否又有问题呢。答案是肯定的。因为,如果在不存储前驱结点,后置结点的情况下,直接一遍遍历,递归的话,肯定会把前驱和后置结点一起反转,所以我们如果硬是要用递归的话,就只能在局部反转的时候用递归。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
//这里也可以递归,反正是个外置函数,无所谓(递归写法)
/*(struct ListNode* reverseLinkedList(struct ListNode* head){
if(head==NULL||head->next==NULL){
return head;
}
struct ListNode* Newhead=reverseLinkedList(head->next);
head->next->next=head;
head->next=NULL;
return Newhead;
}
)*/
void reverseLinkedList(struct ListNode* head){
struct ListNode* pre=NULL;
struct ListNode* cur=head;
while(cur!=NULL){
struct ListNode* nextnode=cur->next;
cur->next=pre;
pre=cur;
cur=nextnode;
}
}
struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
if(left==right){
return head;
}
//增加哑结点,避免不必要的复杂分类讨论
struct ListNode* dummy=malloc(sizeof(struct ListNode));
dummy->val=-1;
dummy->next=head;
struct ListNode* pre=dummy;
//要习惯用for循环,特别是涉及遍历次数可以精确判断的时候,for循环有时能不用像while循环一样在链表里去模拟遍历
//遍历停到left的前一个结点
for(int i=0;i<left-1;i++){
pre=pre->next;
}
//对于变量多的时候,我们要有习惯的去有意的设置变量名,增强代码的可读性
//停到right上
struct ListNode* rightnode=pre;
for(int i=0;i<right-left+1;i++){
rightnode=rightnode->next;
}
//记录结点,方便挂链
struct ListNode* leftnode=pre->next;
struct ListNode* curr=rightnode->next;
//断链
pre->next=NULL;
rightnode->next=NULL;
//反转中间链表
reverseLinkedList(leftnode);
//接链
pre->next=rightnode;
leftnode->next=curr;
return dummy->next;
}
思路2.头插法
由于上一种思路里面我们遍历一次链表后,在反转部分还要再遍历一遍,导致了不必要的遍历,我们是否可以想一个办法只遍历一遍。
这里用到的办法就是头插法。
记录三个位置,一个是left-1的位置,一个是left位置,一个是left->next位置
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
struct ListNode* dummy=malloc(sizeof(struct ListNode));
dummy->val=-1;
dummy->next=head;
struct ListNode* pre=dummy;
for(int i=0;i<left-1;i++){
pre=pre->next;
}
struct ListNode* cur=pre->next;
struct ListNode* next;
for(int i=0; i<right-left; i++){
next=cur->next;
cur->next=next->next;
next->next=pre->next;
pre->next=next;
}
return dummy->next;
}