给你单链表的头指针 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]
提示:
- 链表中节点数目为
n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
【分析】
要求反转指定区间内的链表,那么要找到区间的前驱和后继,然后对中间元素进行反转。
第一步:排除链表只有一个空节点和要反转的两个节点在同一个位置。
第二步:定义一个娅节点,放在链表的前面,以防万一要反转的是第一个节点开始的区间。并定义两个指针,分别指向娅节点和娅节点的后继。
第三步:通过for循环找到left的前驱。此时p为前驱,q为要反转的第一个节点。
第四步:进行反转,定义一个temp指针,用来进行移动反转。最后返回娅节点的后续节点。
具体案例分析:
输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5]
开始时,dummy->head= [1,2,3,4,5],p指向dummy,q指向head(也就是1)。
进行第一个for循环,寻找left的前驱。i=1,i<2,i++=2;此时p=1,q=2,i为2,跳出循环。
进入第二个for循环,进行反转。i=2,i<4,i++=3,首先temp=3,q的后继指向temp的后继(也就是2->4),temp的后继指向p的后继(也就是3->2),然后将p的后继指向temp(也就是1->3)(此时链表为dummy->head=1->3->2->4->5,p指向1,q指向2,temp指向3)。
进行下一轮循环(也就是i=3,i<4,i++=4).首先temp=4,q的后继指向temp的后继(也就是2->5),temp的后继指向p的后继(也就是4->3),然后将p的后继指向temp(也就是1->4)(此时链表为dummy->head=1->4->3->2->5)。
下一轮,i=4,跳出循环,返回,dummy的后继head=1->4->3->2->5。
C语言具体代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
if(head->next==NULL || left==right){
return head;
}
struct ListNode *dummy=(struct ListNode*)malloc(sizeof(struct ListNode));//娅节点
dummy->next=head;//娅节点的后继指向链表
struct ListNode *p=dummy;
struct ListNode *q=p->next;
for(int i=1;i<left;i++){//找到left的前驱
p=q;
q=q->next;
}
for(int i=left;i<right;i++){//反转链表
struct ListNode *temp=q->next;
q->next=temp->next;
temp->next=p->next;
p->next=temp;
}
return dummy->next;//返回反转后的链表
}
时间复杂度O(n);空间复杂度O(1)