1 #include "000库函数.h"
2
3
4
5 struct ListNode {
6 int val;
7 ListNode *next;
8 ListNode(int x) : val(x), next(NULL) {}
9 };
10 //自己解法,比较笨,为用算法,即将所有元素合并再排序
11 ListNode* mergeKLists(vector<ListNode*>& lists) {
12 if (lists.size() < 1)return NULL;
13 vector<int>Nums;
14 ListNode* Res = new ListNode(0);
15 ListNode* q = Res;
16
17 for (auto l : lists) {
18 ListNode*p = l->next;//去除头结点
19 while (p) {
20 Nums.push_back(p->val);
21 p = p->next;
22 }
23 }
24
25 sort(Nums.begin(),Nums.end());
26 for (auto n : Nums) {
27 ListNode* t = new ListNode(0);
28 t->val = n;
29 q->next = t;
30 q = t;
31 }
32 return Res->next;
33
34 }
35 //才用递归思想,进行两两合并排序//递归较为耗时
36 class Solution {
37 public:
38 ListNode* mergeKLists(vector<ListNode*>& lists) {
39 ListNode* rtn = new ListNode(INT_MIN);
40 for (auto node : lists) {
41 rtn = merge(rtn, node);
42 }
43 return rtn->next;
44 }
45 ListNode* merge(ListNode * l1, ListNode* l2) {
46 if (!l1)
47 return l2;
48 if (!l2)
49 return l1;
50 if (l1->val < l2->val)
51 {
52 l1->next = merge(l1->next, l2);
53 return l1;
54 }
55 else
56 {
57 l2->next = merge(l1, l2->next);
58 return l2;
59 }
60 }
61 };
62
63 //用到分治法 Divide and Conquer Approach。简单来说就是不停的对半划分,
64 //比如k个链表先划分为合并两个k / 2个链表的任务,再不停的往下划分,
65 //直到划分成只有一个或两个链表的任务,开始合并。举个例子来说比如合并6个链表,
66 //那么按照分治法,我们首先分别合并0和3,1和4,2和5。这样下一次只需合并3个链表,
67 //我们再合并1和3,最后和2合并就可以了。代码中的k是通过(n + 1) / 2 计算的,
68 //这里为啥要加1呢,这是为了当n为奇数的时候,k能始终从后半段开始,比如当n = 5时,
69 //那么此时k = 3,则0和3合并,1和4合并,最中间的2空出来。当n是偶数的时候,加1也不会有影响,
70 //比如当n = 4时,此时k = 2,那么0和2合并,1和3合并,完美解决问题,参见代码如下:
71
72 class Solution {
73 public:
74 ListNode* mergeKLists(vector<ListNode*>& lists) {
75 if (lists.empty()) return NULL;
76 int n = lists.size();
77 while (n > 1) {
78 int k = (n + 1) / 2;
79 for (int i = 0; i < n / 2; ++i) {
80 lists[i] = mergeTwoLists(lists[i], lists[i + k]);
81 }
82 n = k;
83 }
84 return lists[0];
85 }
86 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
87 ListNode *dummy = new ListNode(-1), *cur = dummy;
88 while (l1 && l2) {
89 if (l1->val < l2->val) {
90 cur->next = l1;
91 l1 = l1->next;
92 }
93 else {
94 cur->next = l2;
95 l2 = l2->next;
96 }
97 cur = cur->next;
98 }
99 if (l1) cur->next = l1;
100 if (l2) cur->next = l2;
101 return dummy->next;
102 }
103 };
104
105 //我们再来看另一种解法,这种解法利用了最小堆这种数据结构,
106 //我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。
107 //然后我们每次取出最小的那个元素加入我们最终结果的链表中,
108 //然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,
109 //以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可,代码如下:
110 class Solution {
111 public:
112 ListNode* mergeKLists(vector<ListNode*>& lists) {
113 auto cmp = [](ListNode*& a, ListNode*& b) {
114 return a->val > b->val;
115 };
116 priority_queue<ListNode*, vector<ListNode*>, decltype(cmp) > q(cmp);
117 for (auto node : lists) {
118 if (node) q.push(node);
119 }
120 ListNode *dummy = new ListNode(-1), *cur = dummy;
121 while (!q.empty()) {
122 auto t = q.top(); q.pop();
123 cur->next = t;
124 cur = cur->next;
125 if (cur->next) q.push(cur->next);
126 }
127 return dummy->next;
128 }
129 };
130 //将所有的结点值出现的最大值和最小值都记录下来,
131 //然后记录每个结点值出现的次数,这样我们从最小值遍历到最大值的时候,
132 //就会按顺序经过所有的结点值,根据其出现的次数,建立相对应个数的结点。
133 //但是这种解法有个特别需要注意的地方,那就是合并后的链表结点都是重新建立的,
134 //若在某些情况下,我们不能新建结点,而只能交换或者重新链接结点的话,那么此解法就不能使用,
135 //但好在本题并没有这种限制,可以完美过OJ,参见代码如下:
136 class Solution {
137 public:
138 ListNode* mergeKLists(vector<ListNode*>& lists) {
139 ListNode *dummy = new ListNode(-1), *cur = dummy;
140 unordered_map<int, int> m;
141 int mx = INT_MIN, mn = INT_MAX;
142 for (auto node : lists) {
143 ListNode *t = node;
144 while (t) {
145 mx = max(mx, t->val);
146 mn = min(mn, t->val);
147 ++m[t->val];
148 t = t->next;
149 }
150 }
151 for (int i = mn; i <= mx; ++i) {
152 if (!m.count(i)) continue;
153 for (int j = 0; j < m[i]; ++j) {
154 cur->next = new ListNode(i);
155 cur = cur->next;
156 }
157 }
158 return dummy->next;
159 }
160 };
161
162 void T023() {
163 vector<ListNode*>lists;
164 srand((int)time(0));
165 for (int i = 0; i < 3; ++i) {
166 ListNode* head,*p;
167 head = new ListNode(0);
168 p = head;
169 for (int j = 0; j < 5; ++j) {
170 ListNode* t = new ListNode(0);
171 t->val = rand() % 100;
172 p->next = t;
173 p = t;
174 }
175 lists.push_back(head);
176 head = head->next;
177 while (head) {
178 cout << head->val << '\t';
179 head = head->next;
180 }
181 cout << endl;
182 }
183 ListNode* L1 = mergeKLists(lists);
184 while (L1) {
185 cout << L1->val << '\t';
186 L1 = L1->next;
187 }
188
189 cout << endl;
190
191
192
193
194
195 }