leetcode023:Merge k Sorted Lists

問題描述

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

問題分析

思路1

這個問題是leetcode021合併兩個有序列表的增強版:合併k個有序列表。
實現原理比較相似:每次取k個列表表頭結點,依次找出這些頭結點最小的(排序,便於後續利用),然後取最小結點所在列表的下一結點。這次學習瞭如何利用sort()函數給vector的非基本類型ListNode排序。

  • 先寫比較函數
bool cmp_by_ListNode(const ListNode *left, const ListNode *right){
     return left->val < right->val;
}
  • 調用sort()排序函數
sort(vecList.begin(), vecList.end(), cmp_by_ListNode);
  • 代碼

待優化

bool cmp_by_ListNode(const ListNode *left, const ListNode *right){
     return left->val < right->val;
}

 class Solution {
 public:
     ListNode *mergeKLists(vector<ListNode *> &lists) {
         int size = lists.size();
         // ListNode *ans_final = NULL;
         ListNode *ans = NULL;
         ListNode *ans_p = NULL;
         vector<ListNode *> vecList;
         for (int i = 0; i < size; i++){
             if (lists[i]) { vecList.push_back(lists[i]); }
         }
         size = vecList.size();
         if (!size) return NULL;
         if (size == 1) return *(vecList.begin());
         sort(vecList.begin(), vecList.end(), cmp_by_ListNode);
         vector<ListNode *>::iterator it;
         ListNode *k = NULL;    //k結點的值來自於上次vecList表頭值(即最小值所在結點)
         int val;
         int flag;              //0:表示k結點的值比vecList中任何結點值都小,此時直接將k結點加入ans列表中,並讓k後續指向k->next
         while (vecList.size() > 1 || vecList.size() == 1 && k){
             it = vecList.begin();
             val = (*it)->val;
             flag = 1;
             if (k){
                 if (k->val <= val){
                     val = k->val;
                     flag = 0;
                 }
                 else{
                     //方案1,加入vecList再排序,複雜度O(n*logn),n爲vecList結點數目,運行時間154 ms
                     /*vecList.push_back(k);
                     sort(vecList.begin(), vecList.end(), cmp_by_ListNode);*/
                     //因爲vecList本身是有序的,所以無需排序,只要將k值插入合適位置即可使得vecList有序(減少計算量)
                     //方案2,直接插入,查找複雜度爲O(n),插入複雜度也是O(n)[因爲是連續內存,後面的元素需要騰出空間],運行時間65 ms
                     /*vector<ListNode *>::iterator loc;
                     for (loc = vecList.begin(); loc != vecList.end(); loc++){
                     if ((*loc)->val > k->val) break;
                     }
                     if (loc != vecList.end()){
                         vecList.insert(loc, k);
                     }
                     else{
                         vecList.push_back(k);
                     }*/
                     //方案2改進:使用二分法查找,運行時間:60 ms
                     int l = 0, r = vecList.size() - 1;
                     int mid =( l + r) / 2;
                     while (l<r){
                         if (k->val < vecList[mid]->val)
                             r = mid;
                         else
                             l = mid;
                         mid = (l + r) / 2;
                         if (mid == l) break;
                     }vector<ListNode *>::iterator loc;
                     if (k->val >= vecList[r]->val) vecList.push_back(k);
                     else if (r - l == 1 && k->val > vecList[l]->val){
                         loc = vecList.begin() + r;
                         vecList.insert(loc, k);
                     }
                     else{
                         loc = vecList.begin() + l;
                         vecList.insert(loc, k);
                     }
                 }
             }
             ListNode *node = new ListNode(val);
             if (!ans) ans_p = ans = node;
             else {
                 ans_p->next = node; ans_p = node;
             }
             if (flag){
                 k = (*it)->next;
                 vecList.erase(it);
             }
             else k = k->next;
         }
         //if (vecList.size() == 1 && (!k)){
             if (!ans) ans = *vecList.begin();
             else ans_p->next = *vecList.begin();
        // }
         return ans;
     }
 };
  • 優化後的代碼
    上述思路每次取最小的思想歸結爲用最小堆,其建堆算法複雜度爲O(n),且代碼簡化。基本和上述代碼性能相當。
//運行時間:61 ms
bool cmp_by_ListNode(const ListNode *left, const ListNode *right){
     return left->val > right->val;
}
class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        int size = lists.size();
        // ListNode *ans_final = NULL;
        ListNode *ans = NULL;
        ListNode *ans_p = NULL;
        vector<ListNode *> vecList;
        for (int i = 0; i < size; i++){
            if (lists[i]) { vecList.push_back(lists[i]); }
        }
        size = vecList.size();
        if (!size) return NULL;
        if (size == 1) return vecList[0];
        make_heap(vecList.begin(), vecList.end(), cmp_by_ListNode);
        ListNode *k = NULL; //k結點的值來自於上次vecList表頭值(即最小值所在結點)
        int val;
        int flag;               //0:表示k結點的值比vecList中任何結點值都小,此時直接將k結點加入ans列表中,並讓k後續指向k->next
        while (vecList.size() > 1 || vecList.size() == 1 && k){
            val = vecList.front()->val;
            flag = 1;
            if (k){
                if (k->val <= val){
                    val = k->val;
                    flag = 0;
                 }
                     else{
                         vecList.push_back(k);
                         push_heap(vecList.begin(), vecList.end(), cmp_by_ListNode);
                     }
                 }
                 ListNode *node = new ListNode(val);
                 if (!ans) ans_p = ans = node;
                 else {
                     ans_p->next = node; ans_p = node;
                 }
                 if (flag){
                     k = vecList.front()->next;
                     pop_heap(vecList.begin(), vecList.end(), cmp_by_ListNode);
                     vecList.pop_back();
                 }
                 else k = k->next;
             }
             //if (vecList.size() == 1 && (!k)){
                 if (!ans) ans = *vecList.begin();
                 else ans_p->next = *vecList.begin();
            // }
             return ans;
    }
};

思路2

直接把k個列表放一個列表裏,然後快排或建最小堆,複雜度O(nlogn)
- 快排代碼

//運行時間:43ms
bool cmp_by_ListNode(const ListNode *left, const ListNode *right){
     return left->val < right->val;
}
class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        int size = lists.size();
        ListNode *ans = NULL;
        ListNode *ans_p = NULL;
        vector<ListNode *> vecList;
        for (int i = 0; i < size; i++){
            if (lists[i]) { vecList.push_back(lists[i]); }
        }
        size = vecList.size();
        if (!size) return NULL;
        if (size == 1) return vecList.front();
        int i = 0;
        while (i<size)
        {
            ListNode*p = vecList[i++];
            while (p->next){
                vecList.push_back(p->next);
                p = p->next;
            }
        }
        sort(vecList.begin(), vecList.end(), cmp_by_ListNode);
        size = vecList.size();
        i = 0;
        while (i<size){
            ListNode * node = new ListNode(vecList[i]->val);
            if (!ans) ans_p = ans = node;
            else { ans_p->next = node; ans_p = node; }
            i++;
        }
        return ans;
    }
};
  • 最小堆代碼
    注:建立最小堆的比較函數是>,最大堆爲<,STL默認建立最大堆。
//運行時間:52ms
bool cmp_by_ListNode(const ListNode *left, const ListNode *right){
     return left->val > right->val;
}
class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        int size = lists.size();
        // ListNode *ans_final = NULL;
        ListNode *ans = NULL;
        ListNode *ans_p = NULL;
        vector<ListNode *> vecList;
        for (int i = 0; i < size; i++){
            if (lists[i]) { vecList.push_back(lists[i]); }
        }
        size = vecList.size();
        if (!size) return NULL;
        if (size == 1) return vecList[0];
        int i = 0;
        while (i<size)
        {
            ListNode*p = vecList[i++];
            while (p->next){
                vecList.push_back(p->next);
                p = p->next;
            }
        }
        make_heap(vecList.begin(), vecList.end(), cmp_by_ListNode);
        while (!vecList.empty()){
            if (!ans) ans_p = ans = vecList.front();
            else{ ans_p->next = vecList.front(); ans_p = vecList.front(); }
            pop_heap(vecList.begin(), vecList.end(), cmp_by_ListNode);
            vecList.pop_back();
        }
        if (ans_p) ans_p->next = NULL;
        // }
        return ans;
    }
};
發佈了60 篇原創文章 · 獲贊 8 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章