刷题训练之链表

> 作者:დ旧言~
> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:熟练掌握链表算法。

> 毒鸡汤:学习,学习,再学习 ! 学,然后知不足。

> 专栏选自:刷题训练营

> 望小伙伴们点赞👍收藏✨加关注哟💕💕 

🌟前言分析

最早博主续写了牛客网130道题,这块的刷题是让同学们快速进入C语言,而我们学习c++已经有一段时间了,知识储备已经足够了但缺少了实战,面对这块短板博主续写刷题训练,针对性学习,把相似的题目归类,系统的刷题,而我们刷题的官网可以参考:​​​​​​

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网

⭐知识讲解

基本思想:

  • 画图,一定要画图,只有画好图才能直观形象便于我们理解。
  • 引入虚拟"头"结点。

  • 不要吝啬空间,大胆去定义变量。

🌙topic-->1

题目链接:1. 两数相加 - 力扣(LeetCode)

 

题目分析:

给一个非空的链表,表示的是两个非负的整数,它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字,然后将两个数字相加,并以相同形式返回一个表示和的链表。

算法原理:

  • 解法:模拟两数相加的过程即可

图解:

细节处理:

  • 判端循环结束标志。
  • 可能存在两个链表长短不一。
  • 不要忘记释放空间。

代码演示:

class Solution 
{
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
    {
        // 定义两个指针
        ListNode* cur1 = l1,*cur2 = l2;
        // 开辟空间(创建一个虚拟头结点,记录最终结果)
        ListNode* newhead = new ListNode(0);
        ListNode* prev = newhead; // 标记尾指针
        int t = 0; // 记录进位
        // 循环
        while(cur1 || cur2 || t) // 细节一:循环结束标志
        {
            // 先加上第一个链表
            if(cur1)
            {
                t = t + cur1->val;
                cur1 = cur1->next;// 指针需要移动
            }
            // 再加上第二个链表
            if(cur2)
            {
                t = t + cur2->val;
                cur2 = cur2->next;// 指针需要移动
            }
            // 开始进位
            prev->next = new ListNode(t % 10);
            prev = prev->next;
            t = t/10;
        }

        prev = newhead->next; // 回到最初位置
        delete newhead;// 释放空间

        return prev;
    }
};

🌙topic-->2

题目链接:2. 两两交换链表中的节点 - 力扣(LeetCode)

 

题目分析:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题。

算法原理:

  • 解法一:采用递归(有兴趣大家自己可以上手写写)
  • 解法二:循环+迭代(模拟)

图解:

细节处理:

  • 判断链表边界情况。
  • 循环结束标志。
  • 不要忘记释放空间。

代码演示:

class Solution
{
public:
    ListNode* swapPairs(ListNode* head)
    {
        // 判断边界情况
        if(head == nullptr || head->next == nullptr) return head;
        // 开辟空间
        ListNode* newHead = new ListNode(0);
        newHead->next = head;
        
        // 定义四个指针
        ListNode* prev = newHead, *cur = prev->next, *next = cur->next, *nnext = next->next;
        while(cur && next) // 循环
        {
            // 交换结点
            prev->next = next;
            next->next = cur;
            cur->next = nnext;

            // 修改指针
            prev = cur; // 注意顺序
            cur = nnext;
            if(cur) next = cur->next;
            if(next) nnext = next->next;
        }
        cur = newHead->next;
        delete newHead;
        return cur;
    }
};

🌙topic-->3

题目链接:3. 重排链表 - 力扣(LeetCode)

 

题目分析:

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

算法原理:

  • 解法:模拟

图解:

细节处理:

  • 判断链表边界情况。

代码演示:

class Solution 
{
public:
    void reorderList(ListNode* head) 
    {
        // 处理边界情况
        if (head == nullptr || head->next == nullptr || head->next->next == nullptr)
            return;
        
        // 1. 找到链表的中间节点 - 快慢双指针(⼀定要画图考虑 slow
        // 的落点在哪⾥)
        ListNode *slow = head, *fast = head;
        while (fast && fast->next) 
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        
        // 2. 把 slow 后⾯的部分给逆序 - 头插法
        ListNode* head2 = new ListNode(0);
        ListNode* cur = slow->next;
        slow->next = nullptr;  // 注意把两个链表给断开
        while (cur) 
        {
            ListNode* next = cur->next;
            cur->next = head2->next;
            head2->next = cur;
            cur = next;
        }
        
        // 3. 合并两个链表 - 双指针
        ListNode* ret = new ListNode(0);
        ListNode* prev = ret;
        ListNode *cur1 = head, *cur2 = head2->next;
        while (cur1) 
        {
            // 先放第⼀个链表
            prev->next = cur1;
            cur1 = cur1->next;
            prev = prev->next;
            // 再放第⼆个链表
            if (cur2) 
            {
                prev->next = cur2;
                prev = prev->next;
                cur2 = cur2->next;
            }
        }
        delete head2;
        delete ret;
    }
};

🌙topic-->4

题目链接:4. 合并 K 个升序链表 - 力扣(LeetCode)

​ 

题目分析:

给你一个链表数组,每个链表都已经按升序排列,请你将所有链表合并到一个升序链表中,返回合并后的链表。

算法原理:

  • 解法:递归+分治

图解:

代码演示:

class Solution
{
public:
    ListNode* mergeKLists(vector<ListNode*>& lists)
    {
        return merge(lists, 0, lists.size() - 1);
    }
    ListNode* merge(vector<ListNode*>& lists, int left, int right)
    {
        if(left > right) return nullptr;
        if(left == right) return lists[left];
        // 1. 平分数组
        int mid = left + right >> 1;
        // [left, mid] [mid + 1, right]
        // 2. 递归处理左右区间
        ListNode* l1 = merge(lists, left, mid);
        ListNode* l2 = merge(lists, mid + 1, right);
        // 3. 合并两个有序链表
        return mergeTowList(l1, l2);
    }
    ListNode* mergeTowList(ListNode* l1, ListNode* l2)
    {
        if(l1 == nullptr) return l2;
        if(l2 == nullptr) return l1;
        // 合并两个有序链表
        ListNode head;
        ListNode* cur1 = l1, *cur2 = l2, *prev = &head;
        head.next = nullptr;
        while(cur1 && cur2)
        {
            if(cur1->val <= cur2->val)
            {
                prev = prev->next = cur1;
                cur1 = cur1->next;
            }
            else
            {
                prev = prev->next = cur2;
                cur2 = cur2->next;
            }
        }
        if(cur1) prev->next = cur1;
        if(cur2) prev->next = cur2;
        return head.next;
    }
};

🌙topic-->5

题目链接:5. K 个一组翻转链表 - 力扣(LeetCode)

 

题目分析:

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

算法原理:

  • 解法:模拟

图解:

代码演示:

class Solution
{
public:
    ListNode* reverseKGroup(ListNode* head, int k)
    {
        // 1. 先求出需要逆序多少组
        int n = 0;
        ListNode* cur = head;
        while(cur)
        {
            cur = cur->next;
            n++;
        }
        n /= k;
        // 2. 重复 n 次:⻓度为 k 的链表的逆序即可
        ListNode* newHead = new ListNode(0);
        ListNode* prev = newHead;
        cur = head;
        for(int i = 0; i < n; i++)
        {
            ListNode* tmp = cur;
            for(int j = 0; j < k; j++)
            {
                ListNode* next = cur->next;
                cur->next = prev->next;
                prev->next = cur;
                cur = next;
            }
            prev = tmp;
        }
        // 把不需要翻转的接上
        prev->next = cur;
        cur = newHead->next;
        delete newHead;
        return cur;
    }
};

🌟结束语

       今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

​​​

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值