此题是反转链表的进阶版,建议先做反转链表(反转链表的题解在上一个文章)。
话不多说先上代码:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
// write code here
if(head==nullptr||head->next==nullptr||m==n) return head;
ListNode* tmp1 = head;
ListNode* tmp2 = head;
//tmp1保持反转的起始位置
for(int i=0;i<m-1;i++){
tmp1 = tmp1->next;
}
//tmp2保存反转的结束位置的下一个
for(int i=0;i<n;i++){
tmp2 = tmp2->next;
}
//开始反转
ListNode* a = nullptr;
ListNode* b = tmp1;
ListNode* c = tmp1->next;
for(int i=0;i<n-m+1;i++){
b->next = a;
a = b;
b = c;
if(b == tmp2) break;
c = c->next;
}
ListNode* tmp3 = nullptr;//用于连接
ListNode* newList = nullptr;//返回结果的表头
if(m>=2){//若反转位置不包括头节点
tmp3 = head;//那么让tmp3初始为头节点
newList = tmp3; //返回结果的表头记录一下tmp3,因为后面tmp3要进行连接向后走
//让tmp3从头走到反转位置的前一个
for(int i=0;i<m-2;i++){
tmp3 = tmp3->next;
}
tmp3->next = a;//再与反转后的链表相连
}
else{//如果反转位置包括头节点,那就让tmp3直接等于反转后的链表
tmp3 = a;//反转位置包括头节点那么头节点也被反转了,所以新的头就是反转后链表的头
newList = tmp3; //返回结果的表头记录一下tmp3,因为后面tmp3要进行连接向后走
}
//最后让tmp3的尾部与tmp2相连
while (tmp3->next!=nullptr) {
tmp3 = tmp3->next;
}
tmp3->next = tmp2;
return newList;//返回结果
}
};
解题思路:
首先,我们要先得到反转那部分的链表。
定义两个标记指针,tmp1:保存反转的起始位置,tmp2:保存反转的结束位置的下一个。
ListNode* tmp1 = head;
ListNode* tmp2 = head;
//tmp1保持反转的起始位置
for(int i=0;i<m-1;i++){
tmp1 = tmp1->next;
}
//tmp2保存反转的结束位置的下一个
for(int i=0;i<n;i++){
tmp2 = tmp2->next;
}
对那部分的链表进行反转,此时前面标记的两个指针就起到作用了,tmp1用于确定反转部分链表的头,tmp2用于最后判断是否已经完成反转。
//开始反转
ListNode* a = nullptr;
ListNode* b = tmp1;
ListNode* c = tmp1->next;
for(int i=0;i<n-m+1;i++){
b->next = a;
a = b;
b = c;
if(b == tmp2) break;
c = c->next;
}
完成了反转就可以开始连接了,这时候又需要两个指针,tmp3用于进行连接,newList用于返回结果,先判断反转的链表包不包括原链表的头节点,如果不包括头节点:tmp3和newList都标记原链表的头,然后让tmp3从头走到反转位置的前一个再与反转后的链表相连,如果包括头节点:那就让tmp3和newList直接等于反转后的链表头即a指针,因为此时的a已经确定为最终结果的头节点了(原来的头结点被转后面去了)。
ListNode* tmp3 = nullptr;//用于连接
ListNode* newList = nullptr;//返回结果的表头
if(m>=2){//若反转位置不包括头节点
tmp3 = head;//那么让tmp3初始为头节点
newList = tmp3; //返回结果的表头记录一下tmp3,因为后面tmp3要进行连接向后走
//让tmp3从头走到反转位置的前一个
for(int i=0;i<m-2;i++){
tmp3 = tmp3->next;
}
tmp3->next = a;//再与反转后的链表相连
}
else{//如果反转位置包括头节点,那就让tmp3直接等于反转后的链表
tmp3 = a;//反转位置包括头节点那么头节点也被反转了,所以新的头就是反转后链表的头
newList = tmp3; //返回结果的表头记录一下tmp3,因为后面tmp3要进行连接向后走
}
最后让tmp3的尾部与tmp2相连,返回结果newList。
//最后让tmp3的尾部与tmp2相连
while (tmp3->next!=nullptr) {
tmp3 = tmp3->next;
}
tmp3->next = tmp2;
return newList;//返回结果