2020-8-04 反转链表Ⅱ
今天比较晚,只写了一种方法–头插法,对于[m,n],我们要做的就是,把m后面的数一个一个的放到m的前面(插到m位置,原本的m自动后移了)
第一次让m+1插到m位置
第二次让m+2插到m位置(注意这里所说的是位置,而非数据,m位置其实是前一次插过来的的m+1)
第三次让m+3插到m位置
以此类推…直到n插入m位置(此时原来的m已经到n位置了)
每一次迭代都插到m位置,经过n-m次迭代,就完成了调换,也就是头插法的本意啦!
举例说明,形象生动
1->2->3->4->5
1->3->2->4->5
1->4->3->2->5
转换完成!
调换过程中的指针变换我们在代码中解释
①自己写的方法,有点累赘~,记下来作对比吧
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n)
{
//这一步不要也可以,个人喜好
if(m == n || !head)
{
return head;
}
//上述所讲的头插法至少有3个节点,这里对只有2个节点的调换的情况单独讨论
if(m==1&&n==2&&!head->next->next)
{
head->next->next = head;
ListNode* temp = head->next;
head->next = NULL;
return temp;
}
//设置一个虚拟节点
struct ListNode dummy;
dummy.next = head;
//pre一开始在-1的位置
ListNode* pre = &dummy;
//pre来到m-1的位置
for(int i=1;i < m;i++)
{
pre = pre->next;
}
//cur在m的位置
ListNode* cur = pre->next;
//开始扫描
for(int j = m;j < n; j++)
{
//m+1插到m位置(交换他们的后驱指针哦!)
//可以看到cur从原本的m现在后移到了m+1的位置
//每一次迭代cur都是指向2,但是它都会在链表上后移一个位置
//而pre是一直没有动的,一直都在m-1的位置,它要指向插过来的数据
//这样每一次迭代都会将cur与后一位进行链表意义上的位置交换直到完成
ListNode* temp=cur->next;
cur->next = temp->next;
temp->next = pre->next;
pre->next = temp;
}
return dummy.next;
}
};
同样思路简洁代码(我太菜了)
class Solution {
public:
//思路:head表示需要反转的头节点,pre表示需要反转头节点的前驱节点
//我们需要反转n-m次,我们将head的next节点移动到需要反转链表部分的首部,需要反转链表部分剩余节点依旧保持相对顺序即可
//比如1->2->3->4->5,m=1,n=5
//第一次反转:1(head) 2(next) 3 4 5 反转为 2 1 3 4 5
//第二次反转:2 1(head) 3(next) 4 5 反转为 3 2 1 4 5
//第三次发转:3 2 1(head) 4(next) 5 反转为 4 3 2 1 5
//第四次反转:4 3 2 1(head) 5(next) 反转为 5 4 3 2 1
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *dummy=new ListNode(-1);
dummy->next=head;
ListNode *pre=dummy;
for(int i=1;i<m;++i)pre=pre->next;
head=pre->next;
for(int i=m;i<n;++i){
ListNode *nxt=head->next;
//head节点连接nxt节点之后链表部分,也就是向后移动一位
head->next=nxt->next;
//nxt节点移动到需要反转链表部分的首部
nxt->next=pre->next;
pre->next=nxt;//pre继续为需要反转头节点的前驱节点
}
return dummy->next;
}
};
②直接翻转法,借鉴我们昨天解决的反转链表Ⅰ,每一次迭代都直接改变指针,1->2直接改为1<-2,最后对头部和尾部的指针进行操作(m接n+1,m-1接n),从而形成局部翻转
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
// 第m-1个节点
ListNode *pre=dummy;
for(int i=1; i<m; i++){
pre = pre->next;
}
// 第m个节点
ListNode *t, *cur=pre->next, *mNode=pre->next;
// 头插法
for(int i=m; i<=n; i++){
t = cur->next;
cur->next = pre->next;
pre->next = cur;
cur = t;
}
// 第m个节点指向第n+1个节点
mNode->next = cur;
return dummy->next;
}
};