力扣刷题攻略链表篇-链表的反转

本文介绍了LeetCode中关于链表反转的三道经典题目,包括206反转链表(完整反转)、92反转链表II(部分反转)和25K个一组翻转链表。通过迭代和递归两种方法详细解析了解题思路,并提供了C++实现代码。
摘要由CSDN通过智能技术生成


文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^

一.206反转链表

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.迭代写法

示意图:
在这里插入图片描述
我们需要使用双指针来记录节点的前后关系,初始化 pre 指针为 null,cur 指针指向头节点,在迭代过程中,需要每次记录当前节点的 next 指针节点,方便后续更新,最后 pre 指针指向反转后的链表的头节点。

C++ 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //双指针法
        ListNode *pre = nullptr, *cur = head;
        while(cur) {
            ListNode *tem = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tem;
        }
        return pre;
    }
};

3.递归写法

示意图:
在这里插入图片描述
在这里插入图片描述
我们需要层层递归找到原始链表的尾部,然后在回溯过程中再依次修改每个结点的 next 指向,最后原始链表的尾部就是新链表的头节点。

C++代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //递归写法
        //终止条件
        if(head == nullptr || head->next == nullptr) { //处理全为空的情况
            return head;
        }

        //递归传入下一个节点,目的是到达最后一个节点
        //newHead一直为5,head分别为4,3,2,1
        ListNode *newHead = reverseList(head->next);
        // cout << newHead->val << endl;
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};

二.92反转链表II

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

这里使用一趟扫描的方法,示意图如下:
在这里插入图片描述
我用绿色表示的是需要反转的链表,我们可以先使用上一题的方法将这一段链表进行反转,反转后的结果就如图片下方所示。

为了后续链表的连接,我们需要记录图中所示的三个节点,分别是 left 左边第一个节点,right 节点以及 right 右边第一个节点

我们根据这几个节点进行后续链表的拼接:
在这里插入图片描述
得到最终链表。

C++ 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
 
        //一趟扫描,需要记录left前面一个节点和right后面一个节点
        //使用虚拟头节点
        ListNode *dummyHead = new ListNode(0, head);
        int idx = 1, n = right - left + 1;
        ListNode *cur = dummyHead;

        //找到left左边位置,用cur记录
        while(idx < left) {
            cur = cur->next;
            idx ++;
        }

        //实现中间链表翻转
        ListNode *cur2 = cur->next;
        ListNode *pre = nullptr;
        idx = 0;
        while(idx < n) {
            ListNode *tem = cur2->next;
            cur2->next = pre;
            pre = cur2;
            cur2 = tem;

            idx ++;
        }
        //此时pre指向了right的位置
        cur->next->next = cur2;
        cur->next = pre;
        
        cur = dummyHead->next;
        delete(dummyHead);
        return cur;


        //




    }

};

三.25K个一组翻转链表

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

这道题目我们需要每次反转特定数目的节点,然后分组进行翻转即可,每次反转完一组,要进行节点更新,方便下一次反转。最后如果有剩余,保持原顺序

使用虚拟头节点处理开头。

第一组反转后结果如下:
在这里插入图片描述
进行节点更新:
ListNode *tem = pre;
cur->next->next = cur2;
pre = cur->next;
cur->next = tem;
cur = pre;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

C++ 代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        //统计一下链表的长度
        int n = 0;
        ListNode *cur = head;
        while(cur) {
            cur = cur->next;
            n ++;
        }
        //统计要进行几次k个数的交换,最后剩下的节点不用逆序
        int x = n / k;

        //使用虚拟头节点进行操作
        ListNode *dummyHead = new ListNode(0, head);
        cur = dummyHead;
        int idx = 0; //交换次数下标的索引
        int idx2 = 0; //每一组k个节点逆序的索引
        ListNode *pre = nullptr;
        ListNode *cur2 = head;
        while(idx ++ < x) {
            // pre = nullptr;
            idx2 = 0;
            while(idx2 ++ < k) {
                ListNode *tem = cur2->next;
                cur2->next = pre;
                pre = cur2;
                cur2 = tem;
            }

            //处理节点赋值,方便下一次循环
            ListNode *tem = pre;
            cur->next->next = cur2;
            pre = cur->next;
            cur->next = tem;
            cur = pre;


        }

        cur = dummyHead->next;
        delete(dummyHead);
        return cur;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo夏末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值