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 << ' '; 179 head = head->next; 180 } 181 cout << endl; 182 } 183 ListNode* L1 = mergeKLists(lists); 184 while (L1) { 185 cout << L1->val << ' '; 186 L1 = L1->next; 187 } 188 189 cout << endl; 190 191 192 193 194 195 }