链表题,图解是行之有效的方法。
本博客总结迭代法,也就是原地反转。
1.反转整个链表
如图所示,我们定义两个指针指向该链表。其中一个前驱指针pre初始化为空节点,它的next指针指向head(相当于虚拟了一个头节点)。另外一个当前指针cur初始化为头节点。
那么,我们要使得1->2 变为2->1。就是使得 cur->nexrt = pre
。但是先这样操作会使得2这个节点丢失了。所以我们要定义一个临时节点temp把2保存下来,也就是`‘ListNode * temp 。操作完之后如下图:
那么接下来,只要迭代就行了,即:pre=cur;cur=temp;
。跳转到下一个状态:
(注意,我们每次反转的是当前节点 cur的next指针)可看上面图解。
接着上述三个操作,我们看看迭代终止条件是什么:我们需要一直反转到5节点的next指针,也就是
可看到,当5节点的next指针被反转后,pre和cur节点依次后移一个,此时pre节点为5节点,cur指向空节点。
所以我们得到迭代终止条件,即:cur==null
,此时新链表的表头为pre节点。
综上所述,我们可以得到链表反转的代码:
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
//不能给-1节点,否则最后反转后会多出来一个。
ListNode *cur = pHead;
ListNode *pre = nullptr;
ListNode *temp;
while(cur!=nullptr)
{
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
//画图可知,最后一次反转链表后,cur->next指向null了,故返回pre。
}
};
2.反转部分链表
如题:我们需要反转给定区间内的链表节点。
思路跟第一题很相似,在第一题时,我们反转的是从head开始到链表尾部。本题,我们只要找到需要反转的开始部分作为head节点后,剩下的操作跟前面的类似。如下图:即找到下图状态为初始状态即可。
前面我们说过,上述迭代反转的方式,是反转当前节点cur的next指针,所以开始迭代时,我们需要使得pre初始化为2,cur初始化为3。
同时最后我们需要使得1节点指向4节点,所以我们需要记录下pre的前一个节点1。
接着我们来看看终止状态,在反转4节点的next指针后,pre和cur依次后移一位。如下:
最后我们可以看到 1-2和4-5之间的指针是断开了,我们需要1->4,2->5。
这时,我们前面保存下来的临时节点temp起作用了。
即:
temp->next->next = cur;// 顺序不能颠倒,否则报错
temp->next = pre;
注意这里顺序不能颠倒,颠倒的话就变为1->4->5了。因为temp->next->next变了。
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *new_head = new ListNode(0);
new_head->next = head;
ListNode *pre = new_head;
for(int i=1;i<m;i++) //找到1这个节点
{
pre = pre->next;
}
ListNode* temp = pre;
pre = pre->next; //2节点
ListNode * cur = pre->next; //3节点
ListNode*temp_1; //迭代的临时节点
for(int i=m;i<n;i++)
{
temp_1 = cur->next;
cur->next = pre;
pre = cur;
cur = temp_1;
}
temp->next->next = cur;// 顺序不能颠倒,否则报错
temp->next = pre;
return new_head->next;
}
};
`