牛客题霸面试真题——链表:NC50 链表中的节点每k个一组翻转

原题链接: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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值