• LeetCode·23.合并K个升序链表·递归·迭代


    链接:https://leetcode.cn/problems/merge-k-sorted-lists/solution/by-xun-ge-v-huf8/
    来源:力扣(LeetCode
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

    题目

    示例

     

     

    思路

    解题思路

    • 暴力解法

    正所谓暴力永不过时,没有暴力解决不了的问题,只有硬件不行,超时就是过

    对于本题,需要合并多个链表,对于链表相关问题,将链表转换为用数组存储基本上都能解决问题,我们将链表所有元素用数组进行存储,然后将数组进行排序,再将数组元素转换到链表中存储即可

    • 逐一比较

    对于暴力求解,显然看着不高级,那就稍微改进一下
    题目给我们的链表已经是升序的了,对于所有链表来说第一个元素都是相对于最小的元素,那么我们按行进行比较,每次取第一行最小的元素加入返回链表中即可。

    接下来的解法就存在两种情况,使用递归实现,还是使用迭代,使用递归对我们自己来说简单易写,但是坏处就是程序资源开销大,迭代就和递归相反了。

    • 对于多个链表合并,可以转换为同一个子问题
    • 任意两个链表合并

    对于任意多个链表,我们都可以对其中两个进行合并,然后在对其中任意两个合并。比如4个链表,先合并其中任意两个 -> 3 个再任意两个合并 -> 2 个再任意两个合并 -> 1个即为所求

    对于任意两个链表合并可以使用迭代和递归实现,对于转换子问题也可以使用递归和迭代两种方法
    迭代可以封装为函数,也可以不需要

    • 递归

    任意两个链表合并递归实现,直接上代码吧


    struct ListNode * dfs(struct ListNode * l1, struct ListNode * l2)
    {
        if(l1 == NULL)
        {
            return l2;
        }
        if(l2 == NULL)
        {
            return l1;
        }
        if(l1->val < l2->val)//比较两个链表元素大小,将小的作为头结点
        {
            l1->next = dfs(l1->next, l2);
            return l1;
        }
        l2->next = dfs(l1, l2->next);
        return l2;
    }

    转换子问题递归实现 -> 其实就是归并排序思路 或者分治思路,看下面代码 

    • 迭代

    任意两个链表合并迭代实现,直接上代码吧


        struct ListNode * iterate(struct ListNode * l1, struct ListNode * l2)
        {
            struct ListNode * head = malloc(sizeof(struct ListNode));
            struct ListNode * tail = head;
            while(l1 && l2){
                if (l1->val <= l2->val){
                    tail->next = l1;
                    l1 = l1->next;
                }
                else{
                    tail->next = l2;
                    l2 = l2->next;
                }
                tail = tail->next;
            }
            tail->next = l1 ? l1 : l2;
            return head->next;
        }


    对于转换子问题迭代实现,看下面代码

    代码

    • 暴力解法
    1. /**
    2.  * Definition for singly-linked list.
    3.  * struct ListNode {
    4.  *     int val;
    5.  *     struct ListNode *next;
    6.  * };
    7.  */
    8. int cmp(const void * a, const void * b)//升序子函数
    9. {
    10.     return *(int *)a - *(int *)b;
    11. }
    12. struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    13.     if(listsSize == 0 )
    14.     {
    15.         return NULL;
    16.     }
    17.     int ans[10000];//临时保存链表值
    18.     int node = 0;
    19.     for(int i = 0; i //保存所有链表值
    20.     {
    21.         while(lists[i])
    22.         {
    23.             ans[node++] = lists[i]->val;
    24.             lists[i] = lists[i]->next;
    25.         }
    26.     }
    27.     qsort(ans, node, sizeof(int), cmp);//排序
    28.     struct ListNode * h = NULL;
    29.     struct ListNode * root = NULL;
    30.     for(int i = 0; i < node; i++)//转换为链表存储
    31.     {
    32.         struct ListNode * r = malloc(sizeof(struct ListNode));
    33.         r->val = ans[i];
    34.         r->next = NULL;
    35.         if(root == NULL)
    36.         {
    37.             h = r;
    38.             root = r;
    39.         }
    40.         else
    41.         {
    42.             h->next = r;
    43.             h = r;
    44.         }  
    45.     }
    46.     return root;
    47. }

    • 逐一比较
    1. struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    2.     int i = 0, j = 0, m = 0;
    3.     struct ListNode *head = malloc(sizeof(struct ListNode));  //头结点
    4.     head->next = NULL;
    5.     struct ListNode *tail = head, *min = head;
    6.     while(1){
    7.         for(i = 0; (i < listsSize) && !lists[i]; i++){
    8.                                     //找到链表数组里第一个非空的元素
    9.         }
    10.         if(i < listsSize){
    11.             min = lists[i];
    12.             m = i;
    13.         }
    14.         else{                            //链表全空,退出循环
    15.             break;
    16.         }
    17.         for(j=i+1; j//记录链表最小结点的位置
    18.             if(lists[j] && (lists[j]->val < min->val)){
    19.                 min = lists[j];
    20.                 m = j;
    21.             }
    22.         }
    23.         tail->next = min;                     //将最小结点加入head链表
    24.         tail = tail->next;
    25.         lists[m] = lists[m]->next;
    26.     }
    27.     return head->next;
    28. }

    • 转换子问题递归实现 -> 其实就是归并排序思路 或者分治思路
    1. //递归实现
    2. struct ListNode * dfs(struct ListNode * l1, struct ListNode * l2)
    3. {
    4.     if(l1 == NULL)
    5.     {
    6.         return l2;
    7.     }
    8.     if(l2 == NULL)
    9.     {
    10.         return l1;
    11.     }
    12.     if(l1->val < l2->val)
    13.     {
    14.         l1->next = dfs(l1->next, l2);
    15.         return l1;
    16.     }
    17.     l2->next = dfs(l1, l2->next);
    18.     return l2;
    19. }
    20. struct ListNode* TwoLists(struct ListNode** lists, int l, int r){//递归分治
    21.     if(l == r)  return lists[l];
    22.     if(l > r)  return NULL;
    23.     int mid = l + (r - l)/2;
    24.     struct ListNode *l1 = TwoLists(lists, l, mid);//任意两个链表之一
    25.     struct ListNode *l2 = TwoLists(lists, mid+1, r);//任意两个链表之一
    26.     /*
    27.     //迭代方法
    28.     struct ListNode * head = malloc(sizeof(struct ListNode));
    29.     struct ListNode * tail = head;
    30.     while(l1 && l2){
    31.         if (l1->val <= l2->val){
    32.             tail->next = l1;
    33.             l1 = l1->next;
    34.         }
    35.         else{
    36.             tail->next = l2;
    37.             l2 = l2->next;
    38.         }
    39.         tail = tail->next;
    40.     }
    41.     tail->next = l1 ? l1 : l2;
    42.     return head->next;
    43.     */
    44.     //递归方法
    45.     return dfs(l1, l2);
    46. }
    47. struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    48.     if(!listsSize)  return NULL;
    49.     return TwoLists(lists, 0, listsSize-1);//将多个链表合并转换为任意两个链表合并,转换子问题
    50. }
    • 转换子问题迭代实现
    1. //递归方法
    2. struct ListNode * dfs(struct ListNode * l1, struct ListNode * l2)
    3. {
    4. if(l1 == NULL)
    5. {
    6. return l2;
    7. }
    8. if(l2 == NULL)
    9. {
    10. return l1;
    11. }
    12. if(l1->val < l2->val)
    13. {
    14. l1->next = dfs(l1->next, l2);
    15. return l1;
    16. }
    17. l2->next = dfs(l1, l2->next);
    18. return l2;
    19. }
    20. //迭代方法
    21. struct ListNode * bfs(struct ListNode * l1, struct ListNode * l2)
    22. {
    23. struct ListNode * head = malloc(sizeof(struct ListNode));
    24. struct ListNode * tail = head;
    25. while(l1 && l2){
    26. if (l1->val <= l2->val){
    27. tail->next = l1;
    28. l1 = l1->next;
    29. }
    30. else{
    31. tail->next = l2;
    32. l2 = l2->next;
    33. }
    34. tail = tail->next;
    35. }
    36. tail->next = l1 ? l1 : l2;
    37. return head->next;
    38. }
    39. struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    40. if(!listsSize) return NULL;
    41. struct ListNode * head = NULL;
    42. for(int i = 0; i < listsSize; i++)
    43. {
    44. //递归实现
    45. head = dfs(head, lists[i]);
    46. //迭代实现
    47. //head = bfs(head, lists[i]);
    48. }
    49. return head;
    50. }

    时间空间复杂度

     

  • 相关阅读:
    screen_main.c
    大学生网课答案查询公众号搭建教程
    《Ubuntu20.04环境下的ROS进阶学习1》
    kubernetes pod日志查看用户创建
    MySQL基础入门教程(InsCode AI 创作助手)
    Impedit odio facilis ad.Quinze également passer billet mensonge animer libre.
    【笔记篇】13供应链项目养成记——之《实战供应链》
    快速清除PPT缓存文件或C盘隐藏大文件
    数据结构之赫曼夫树(哈曼夫树)
    【Spring中的设计模式】
  • 原文地址:https://blog.csdn.net/m0_64560763/article/details/126076674