• 【牛客网面试必刷TOP101】链表篇(三)


    一、前言

    链表是数据结构中重要的一个章节,他的重要性也不言而喻,在未来不管是笔试还是面试都会遇到这类的题目,所以接下来我就会把一些链表的常考的题目全部整理出来供大家学习指正。


    二、学习刷题网站

    在这里插入图片描述

    点击下面链接即可进行刷题学习
    开始刷题

    三、刷题

    先说明一下一些题目取自牛客网面试必刷TOP101
    里面的一些题目在我以前的文章详细写到过,如果没有用新的方法就不会再做讲解
    链表题目(一)
    链表题目(二)
    环状链表

    <1>单链表的排序

    题目链接

    描述:

    给定一个节点数为n的无序单链表,对其按升序排序。
    数据范围:0 要求:时间复杂度 O(nlogn)

    示例1

    输入:{1,3,2,4,5}
    返回值:{1,2,3,4,5}

    示例2

    输入:{-1,0,-2}
    返回值:{-2,-1,0}

    思路分析:

    ①模拟数组

    把每个节点的地址放到数组中,然后在数组中对他们的值进行排序,最后在重新构建链表。

    int cmp(struct ListNode** e1, struct ListNode** e2)
    {
        return (*e1)->val - (*e2)->val;
    }
    
    struct ListNode* sortInList(struct ListNode* head ) {
        if(head == NULL)
        {
            return NULL;
        }
        struct ListNode* nums[100000];
        int count = 0;
        struct ListNode* cur = head;
        while(cur)
        {
            nums[count++] = cur;
            cur = cur->next;
        }
        qsort(nums, count, sizeof(struct ListNode*), cmp);
        head = nums[0];
        cur = head;
        for(int i = 1; i < count; i++)
        {
            cur->next = nums[i];
            cur = cur->next;
        }
        cur->next = NULL;
        return head;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    归并排序

    前面我们做过合并两个有序链表,那我们这个题也可以用这种思路,从中间节点的前一个节点断开,合并两个链表,那么怎么分成两个链表呢,得用到三个指针:

    前面我们写过找到中间节点的题目,就是快慢指针,现在我们要找到中间节点的前一个,那么就让slow和fast指针都先走一次,mid就在他们的中间,fast走到尾即可。

    奇数情况:
    在这里插入图片描述
    偶数情况:
    在这里插入图片描述
    但是我们拆分完以后发现两个链表不一定为有序的,这时候就要用到归并思想:

    如果我们把链表分成单个的节点,那么每个节点都是有序的,然后就可以用合并两个有序链表的方法,怎么把链表分成单个节点呢?答案是递归,如此一来每次要排序的都是有序链表。

    对于递归排序在以前的文章里有过详细讲解:
    八大排序,你都掌握了吗?

    //合并两个有序链表
    struct ListNode* _sortInList(struct ListNode* n1, struct ListNode* n2)
    {
        if(n1 == NULL)
        {
            return n2;
        }
        if(n2 == NULL)
        {
            return n1;
        }
        struct ListNode* head;
        //小的值链接到下一个
        if(n1->val < n2->val)
        {
            head = n1;
            head->next= _sortInList(n1->next, n2);
        }
        else
        {
            head = n2;
            head->next= _sortInList(n1, n2->next);
        }
        return head;
    }
    
    struct ListNode* sortInList(struct ListNode* head ) {
        if(head == NULL || head->next == NULL)
        {
            return head;
        }
        struct ListNode* slow = head, *mid = head->next, *fast = head->next->next;
        while(fast && fast->next)
        {
            slow = slow->next;
            mid = mid->next;
            fast = fast->next->next;
        }
        slow->next = NULL;
        struct ListNode* node1 = sortInList(head);
        struct ListNode* node2 = sortInList(mid);
        struct ListNode* new = _sortInList(node1, node2);
        return new;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    <2>链表的奇偶重排

    题目链接

    描述

    给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。
    注意是节点的编号而非节点的数值。
    数据范围:节点数量满足 0 ≤ n ≤ 10^5,节点中的值都满足0≤val≤1000
    要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

    示例1

    输入:{1,2,3,4,5,6}
    返回值:{1,3,5,2,4,6}
    说明:
    1->2->3->4->5->6->NULL
    重排后为
    1->3->5->2->4->6->NULL

    示例2

    输入:{1,4,6,3,7}
    返回值:{1,6,7,4,3}
    说明:
    1->4->6->3->7->NULL
    重排后为
    1->6->7->4->3->NULL
    奇数位节点有1,6,7,偶数位节点有4,3。重排后为1,6,7,4,3

    备注:
    链表长度不大于200000。每个数范围均在int内。

    思路分析:

    双指针

    我们可以利用两个指针,把奇数节点串成一个链表,偶数位串成一个链表,最后再把两个链表相连接。
    这里最重要的是条件判断,一定要画图!!!
    我们可以只判断偶数节点和偶数节点的下一位不为空,那么一定可以达成条件:
    在这里插入图片描述

    这是有奇数个节点的情况,结尾自动链接到NULL,如果是偶数个节点,就是以cur->next == NULL为结束标志,那么他的结尾也是自动为NULL。

    struct ListNode* oddEvenList(struct ListNode* head ) {
        //如果链表为空,不用重排
            if(head == NULL)
                return head;
            //cur开头指向第二个节点,可能为空
            struct ListNode* cur = head->next;
            //prev开头指向第一个节点
            struct ListNode* prev = head;
            //指向cur开头
            struct ListNode* evenhead = cur;
            while(cur != NULL && cur->next != NULL){
                //偶数节点链接
                prev->next = cur->next;
                prev = prev->next;
                //奇数节点链接
                cur->next = prev->next;
                cur = cur->next;
            }
            //奇偶链表相连
            prev->next = evenhead;
            return head;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    三、小结

    在做题前一定要先画好图,尽量想好特殊情况,考虑好结束条件。
    链表篇就到此结束,接下来博主会更新更多的题目

    点击链接一起刷题吧



  • 相关阅读:
    【深度学习】ResNet网络详解
    智能DNS云解析的宕机切换是如何实现的?-中科三方
    什么是Node.js的流(stream)?它们有什么作用?
    修改pip默认安装位置
    [附源码]Python计算机毕业设计Django高校社团管理系统
    SpringCloud微服务实战——搭建企业级开发框架(三十八):搭建ELK日志采集与分析系统
    订单拆分总结
    Java项目(三)-- SSM开发社交网站(8)--实现会员交互功能
    LeetCode 面试题 16.17. 连续数列
    一起来作画吧「GitHub 热点速览 v.22.14」
  • 原文地址:https://blog.csdn.net/qq_66314292/article/details/126334882