• 【堆】23. Merge k Sorted Lists


    问题:

    给定k个有序链表,将这些链表的所有节点排序,组合成一个新的有序链表

    Example 1:
    Input: lists = [[1,4,5],[1,3,4],[2,6]]
    Output: [1,1,2,3,4,4,5,6]
    Explanation: The linked-lists are:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    merging them into one sorted list:
    1->1->2->3->4->4->5->6
    
    Example 2:
    Input: lists = []
    Output: []
    
    Example 3:
    Input: lists = [[]]
    Output: []
     
    Constraints:
    k == lists.length
    0 <= k <= 10^4
    0 <= lists[i].length <= 500
    -10^4 <= lists[i][j] <= 10^4
    lists[i] is sorted in ascending order.
    The sum of lists[i].length won't exceed 10^4.
    

      

    解法:

    解法一:Min Heap (最小堆)

    首先最小堆的实现:

    class minHeap {
    private:
        vector<ListNode*> heapary;
    public:
        int n; //size
        minHeap() {
            n=0;
        }
    };

    操作:

    • push:插入一个元素
    • popmin:弹出最小元素
     1     void push(ListNode* val) {
     2         heapary.push_back(val);
     3         n++;
     4         swim(n-1);
     5     }
     6     ListNode* popmin() {
     7         ListNode* res = heapary[0];
     8         if(heapary[0]->next==NULL) {
     9             swap(heapary[0], heapary[n-1]);
    10             heapary.pop_back();
    11             n--;
    12         } else {
    13             heapary[0] = heapary[0]->next;
    14         }
    15         sink(0);
    16         return res;
    17     }

    堆适应化:

    • swim:将底层新元素上升,使得堆适应化。(一般在插入push操作中使用<一般从数组尾部(堆底)插入>)
    • sink:将上层新元素下降,使得堆适应化。(一般在删除popmin操作中使用<swap堆顶和堆尾,删除移动后的堆尾,将新的堆顶下降>)
     1     void swim(int i) {
     2         int father = parent(i);
     3         while(father>=0 && heapary[father]->val > heapary[i]->val) {
     4             swap(heapary[father], heapary[i]);
     5             i = father;
     6             father = parent(i);
     7         }
     8     }
     9     void sink(int i) {
    10         int l = left(i);
    11         int r = right(i);
    12         int minchild;
    13         while(l<n) {
    14             minchild = l;
    15             if(r<n && heapary[r]->val<heapary[minchild]->val) {
    16                 minchild = r;
    17             }
    18             if(heapary[minchild]->val >= heapary[i]->val) break;
    19             swap(heapary[minchild], heapary[i]);
    20             i = minchild;
    21             l = left(i);
    22             r = right(i);
    23         }
    24     }

    另外,这里常用求node i 的父节点,子节点:

    • parent(i):(i-1)/2
    • child(i):
      • leftchild(i): i*2+1
      • rightchild(i): i*2+2
    1     int parent(int i) {
    2         return (i-1)/2;
    3     }
    4     int left(int i) {
    5         return i*2+1;
    6     }
    7     int right(int i) {
    8         return i*2+2;
    9     }

    对本题:

    利用上述最小堆,将每个list的头节点放入堆中push(list),

    每次弹出堆顶popmin,作为当前最小值,

    ⚠️ 注意:

    • 弹出堆顶时,若该节点为头的list还不为NULL,
      • 那么该节点->next最为新的堆顶,同时sink这个新堆顶,进行堆适应化。
    • 若该节点为头的list除了该节点外,无剩余节点,
      • 那么swap(堆底,堆顶),heap_size--(删除新堆底),同时sink这个新堆顶,进行堆适应化。

    每次,将上次弹出的最小值->next=本次弹出的当前最小值

    最终得到所求结果。

    代码参考:

     1 class Solution {
     2 public:
     3     ListNode* mergeKLists(vector<ListNode*>& lists) {
     4         minHeap mh;
     5         ListNode* res = NULL, *p = NULL;
     6         for(ListNode* list : lists) {
     7             if(list) mh.push(list);
     8         }
     9         while(mh.n>0) {
    10             if(!res) {
    11                 res = mh.popmin();
    12                 p = res;
    13             } else {
    14                 p->next = mh.popmin();
    15                 p = p->next;
    16             }
    17         }
    18         return res;
    19     }
    20 };

    leetcode解答完整代码:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode() : val(0), next(nullptr) {}
     7  *     ListNode(int x) : val(x), next(nullptr) {}
     8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     9  * };
    10  */
    11 class minHeap {
    12 private:
    13     vector<ListNode*> heapary;
    14     int parent(int i) {
    15         return (i-1)/2;
    16     }
    17     int left(int i) {
    18         return i*2+1;
    19     }
    20     int right(int i) {
    21         return i*2+2;
    22     }
    23     void swim(int i) {
    24         int father = parent(i);
    25         while(father>=0 && heapary[father]->val > heapary[i]->val) {
    26             swap(heapary[father], heapary[i]);
    27             i = father;
    28             father = parent(i);
    29         }
    30     }
    31     void sink(int i) {
    32         int l = left(i);
    33         int r = right(i);
    34         int minchild;
    35         while(l<n) {
    36             minchild = l;
    37             if(r<n && heapary[r]->val<heapary[minchild]->val) {
    38                 minchild = r;
    39             }
    40             if(heapary[minchild]->val >= heapary[i]->val) break;
    41             swap(heapary[minchild], heapary[i]);
    42             i = minchild;
    43             l = left(i);
    44             r = right(i);
    45         }
    46     }
    47 public:
    48     int n;
    49     minHeap() {
    50         n=0;
    51     }
    52     void push(ListNode* val) {
    53         heapary.push_back(val);
    54         n++;
    55         swim(n-1);
    56     }
    57     ListNode* popmin() {
    58         ListNode* res = heapary[0];
    59         if(heapary[0]->next==NULL) {
    60             swap(heapary[0], heapary[n-1]);
    61             heapary.pop_back();
    62             n--;
    63         } else {
    64             heapary[0] = heapary[0]->next;
    65         }
    66         sink(0);
    67         return res;
    68     }
    69 };
    70 
    71 class Solution {
    72 public:
    73     ListNode* mergeKLists(vector<ListNode*>& lists) {
    74         minHeap mh;
    75         ListNode* res = NULL, *p = NULL;
    76         for(ListNode* list : lists) {
    77             if(list) mh.push(list);
    78         }
    79         while(mh.n>0) {
    80             if(!res) {
    81                 res = mh.popmin();
    82                 p = res;
    83             } else {
    84                 p->next = mh.popmin();
    85                 p = p->next;
    86             }
    87         }
    88         return res;
    89     }
    90 };
    完整代码

    解法二:C++ priotity queue(优先队列)

    类似上述最小堆。

    构造方法:

    priority_queue<ListNode*, vector<ListNode*>, cmp>
    • ListNode*:每个元素的类型
    • vector<ListNode*>:优先队列的存储方式:vector
    • cmp:比较方式
      • 默认:less:<,最大堆

    本题中,需要构建最小堆,因此通过重载operator方法实现:

    1     struct cmp {//min heap(greater '>')
    2         //(default: max heap-> less '<')
    3         bool operator()(ListNode *a, ListNode *b) {
    4             return a->val > b->val;
    5         }
    6     };

    代码参考:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode() : val(0), next(nullptr) {}
     7  *     ListNode(int x) : val(x), next(nullptr) {}
     8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     9  * };
    10  */
    11 class Solution {
    12 public:
    13     struct cmp {//min heap(greater '>')
    14         //(default: max heap-> less '<')
    15         bool operator()(ListNode *a, ListNode *b) {
    16             return a->val > b->val;
    17         }
    18     };
    19     ListNode* mergeKLists(vector<ListNode*>& lists) {
    20         priority_queue<ListNode*, vector<ListNode*>, cmp> mh;
    21         ListNode* res = NULL, *p = NULL;
    22         for(ListNode* list : lists) {
    23             if(list) mh.push(list);
    24         }
    25         while(!mh.empty()) {
    26             if(!res) {
    27                 res = mh.top();
    28                 p = res;
    29             } else {
    30                 p->next = mh.top();
    31                 p = p->next;
    32             }
    33             mh.pop();
    34             if(p->next){
    35                 mh.push(p->next);
    36             }
    37         }
    38         return res;
    39     }
    40 };
  • 相关阅读:
    ParamCount、ParamStr
    写一个可拖动的 TShape 回复 "韦韦" 的问题
    读十六进制文本到 Btye 数组的函数 回复 "峰哥!!!" 的问题
    网站速度优化
    [新功能]新增分类浏览页面
    [CN.Text开发笔记]嵌套Repeater的问题
    中秋祝福
    10 Golden rules for publishing your blog
    HttpCompressionModule 6的一个Bug及使用效果
    [CN.Text开发笔记]OnInit与运行期数据绑定
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13872476.html
Copyright © 2020-2023  润新知