原题链接:https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e
关联企业:腾讯、字节、京东
答案参考自:https://blog.nowcoder.net/n/147174dd168444a591656c82ee055d38
(1)已知完全反转以a为头结点的链表(尾节点->next=nullptr)需要设置前驱为pre=nullptr
;那么当反转前尾节点->next不再是nullptr,而是节点b时,前驱pre=?
为了解答这个疑问,需要注意一个问题:当实现完全的翻转链表时,为什么初始化pre=nullptr?
因为我们希望pre表示为前驱,而初始化的时候pre=head的前驱,那么head的前驱是哪个节点呢?这就要反着进行推导了,如果我们知道反转后head的下一个节点,那么该节点就是反转前head的前驱!
如果反转前尾节点->next=nullptr,由于当反转结束时head从头节点变为了尾节点,所以head->next=nullptr。也就是说反转前head的前驱是nullptr,所以才将pre初始化为null
。
如果反转前尾节点->next=b,同理,当反转结束时head从头节点变为了尾节点,若想保证反转后链表的正确性那么,head->next=b,所以初始化时pre表示head的前驱也就是pre=b
!
(2)由(1)知,我们需要知道反转区间的下一个节点来初始化pre,所以函数Reverse_a_b(head,p)实现的是区间[head,p的前一个节点]
之间的反转,从head开始找到间隔k的节点p,其反转后的新头节点由res来接收。注意:一开始head指向第一个节点但翻转后,head指向第一轮翻转后的最后一个节点。
(3)对于下一组的反转可以使用递归来更新,即 reverseKGroup(p,k)
:将上一轮的p作为下一轮的head,然后对剩余的节点按照组为单位翻转。递归时这里一定要使用head->next来接收reverseKGroup(p,k)
的返回值,在不断的向下递归中传入参数的头节点是在变化的,上一轮的头节点在反转后变为尾节点,只有递归到底部时,res(下一轮的反转后新头节点)才会向上返回,此时需要将上下两轮的链表进行连接:即上一轮的尾节点(表示为head)下一轮的头节点(表示为res)进行连接:head->next=reverseKGroup(p,k)
,否则最后只剩一组链表了。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
ListNode* Reverse_a_b(ListNode *a,ListNode *b){
ListNode *pre=b;
ListNode *cur=a;
ListNode *ne=nullptr;
while(cur!=b){
ne = cur->next;
cur->next=pre;
pre=cur;
cur=ne;
}
return pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
ListNode *tail=head;
for(int i=0;i<k;i++){
//当组长>链表长度 则不翻转链表,直接返回head
if(tail==nullptr) return head;
tail=tail->next;
}
//每次运行更新一组res
auto res = Reverse_a_b(head, tail);
head->next=reverseKGroup(tail,k);
return res;
}
};