• Merge k Sorted Lists leetcode


    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 

     
    题目意思就是合并多个有序链表!采用分治递归!
    第一种思路分析:分而治之,不断划分,直到变成两个有序链表合并的子问题!归并的动态图如右图所示:
     
    本题建立在合并两个有序链表算法的基础之上,不断合并两个有序子链表,直到整个子链表合而为一。这道题目在分布式系统中非常常见,来自不同client的sorted list要在central server上面merge起来。
    我们来分析一下上述算法的时间复杂度。假设总共有k个list,每个list的最大长度是n,那么运行时间满足递推式T(k) = 2T(k/2)+O(n*k)。根据主定理,可以算出算法的总复杂度是O(nklogk)。如果不了解主定理的朋友,可以参见 主定理-维基百科 。空间复杂度的话是递归栈的大小O(logk)。 
    代码实现如下:
     1 #include<iostream>
     2 #include<vector>
     3 using namespace std;
     4 
     5 struct ListNode {
     6     int val;
     7     ListNode *next;
     8     ListNode(int x) : val(x), next(NULL) {}
     9 };
    10 
    11 class Solution {
    12 public:
    13     ListNode* mergeKLists(vector<ListNode*>& lists) 
    14     {
    15         if (lists.size() == 0)
    16             return NULL;
    17         if (lists.size() == 1)
    18             return lists[0];
    19         //vector<ListNode*> res;
    20         while (lists.size()!=1)
    21         {
    22             ListNode*temp= mergeTwoLists(lists[0], lists[1]);
    23             lists.push_back(temp);
    24             lists.erase(lists.begin());
    25             lists.erase(lists.begin());
    26         }
    27         return lists[0];
    28 
    29     }
    30     ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
    31     {
    32         if (!l1)
    33             return l2;
    34         if (!l2)
    35             return l1;
    36         ListNode n1(-1);
    37         n1.next = l1;
    38         ListNode *ptr1 = l1, *pre1, *ptr2 = l2, *b2;
    39         pre1 = &n1;
    40         while (ptr2)
    41         {
    42             b2 = ptr2->next;
    43             if (ptr1->val < ptr2->val)
    44             {
    45                 ptr1 = ptr1->next;
    46                 pre1 = pre1->next;///
    47                 if (ptr1 == NULL)//这儿必须让其终止!否则运行会出错的
    48                     break;
    49             }
    50             else
    51             {
    52                 pre1->next = ptr2;
    53                 ptr2->next = ptr1;
    54                 ptr2 = b2;
    55                 pre1 = pre1->next;///
    56             }
    57         }
    58         if (ptr2 != NULL)
    59             pre1->next = ptr2;
    60         return n1.next;
    61     }
    62 };
    63 
    64 int main()
    65 {
    66     Solution test;
    67 
    68     vector<ListNode*> val;
    69     ListNode *n1 = NULL;
    70     ListNode n2(-1),n3(5),n4(11);
    71     n2.next = &n3;
    72     n3.next = &n4;
    73     ListNode *n5 = NULL;
    74     ListNode n6(6), n7(10);
    75     n6.next = &n7;
    76     val.push_back(n1);
    77     val.push_back(&n2);
    78     val.push_back(n5);
    79     val.push_back(&n6);
    80     //cout << "the size of val:" << val.size() << " " << val.capacity() << endl;
    81     ListNode* result = test.mergeKLists(val);
    82     while (result)
    83     {
    84         cout << result->val << " ";
    85         result = result->next;
    86     }
    87     return 0;
    88 }
    View Code

    第二种思路分析(用到了堆这种数据结构):思路比较难想到,但是其实原理比较简单。维护一个大小为k的堆,每次取堆顶的最小元素放到结果中,然后读取该元素的下一个元素放入堆中,重新维护好。因为每个链表是有序的,每次又是去当前k个元素中最小的,所以当所有链表都读完时结束,这个时候所有元素按从小到大放在结果链表中。这个算法每个元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是O(nklogk)。空间复杂度是堆的大小,即为O(k)。

     
     
     
     
     
    手里拿着一把锤子,看什么都像钉子,编程界的锤子应该就是算法了吧!
  • 相关阅读:
    Scanner和BufferedReader
    java annotation
    java获取短uuid
    定时任务线程
    sql 查询最近30分钟或者自定义时间数据
    查看base64编码图片
    oracle 的PACKAGE恢复过程
    Oracle BFILE备忘
    读取Spring的配置文件applicationContext.xml的5种方法
    解决eclipse ctrl+鼠标左键不能用
  • 原文地址:https://www.cnblogs.com/chess/p/4743881.html
Copyright © 2020-2023  润新知