1.合并两个有序数组
将两个按升序排列的数组仍按升序合并存放到另一个数组中,要求每个
数都一次到位,不得在新数组中重新排序。
#include <stdio.h>
int main(void)
{
int b[5] = {1, 6, 17, 56, 72};
int a[5] = {7, 23, 32, 33, 82};
int c[10], i, j, k, p;
i = j = k = 0; //i 对应 a 数组,j 对应 b 数组,k 对应 c 数组;
while (i < 5 && j < 5) //判断 a,b 两数组是否比较完毕;
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
if (i > 4) //把 b 赋给 c
{
for (p = j; p < 5; p++)
c[k++] = b[p];
}
if (j > 4) //把 a 赋给 c
{
for (p = i; p < 5; p++)
c[k++] = a[p];
}
for (i = 0; i < 10; i++) //输出 c
printf("%4d", c[i]);
printf("\n");
}
2.合并两个有序链表
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//遍历解法
class Solution
{
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
{
ListNode result = ListNode(-100);
ListNode *test = &result;
ListNode *temp1 = l1;
ListNode *temp2 = l2;
while (temp1 && temp2)
{
//注意这里判断了相等的情况
//temp1->val == temp2->val
if (temp1->val <= temp2->val)
{
test->next = temp1;
temp1 = temp1->next;
test = test->next;
}
else
{
test->next = temp2;
temp2 = temp2->next;
test = test->next;
}
}
if (temp1)
test->next = temp1;
if (temp2)
test->next = temp2;
return result.next;
}
};
//递归解法
class Solution
{
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
{
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
//还是判断了相等
if (l1->val <= l2->val)
{
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
else
{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
3.合并K个排序链表
思路1:分治法
简单来说就是不停的对半划分,比如k个链表先划分为合并两个k/2个链表的任务,再不停的往下划分,直到划分成只有一个或两个链表的任务,才开始进行合并
。举个例子来说比如合并6个链表,那么按照分治法,我们首先分别合并0和3,1和4,2和5。这样下一次只需合并3个链表,我们再合并1和3,最后和2合并就可以了。
代码中的k是通过 (n+1)/2 计算的,这里为啥要加1呢,这是为了当n为奇数的时候,k能始终从后半段开始,比如当n=5时,那么此时k=3,则0和3合并,1和4合并,最中间的2空出来。当n是偶数的时候,加1也不会有影响,比如当n=4时,此时k=2,那么0和2合并,1和3合并,完美解决问题.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int len = lists.size();
if (len == 0) return NULL;
while (len > 1) {
int k = (len + 1) / 2;
for (int i = 0; i < len / 2; ++i) {
lists[i] = mergeTwoLists(lists[i], lists[i + k]);
}
len = k;
}
return lists[0];
}
private:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
{
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
if (l1->val <= l2->val)
{
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
else
{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
思路2:最小堆的数据结构
我们再来看另一种解法,这种解法利用了最小堆这种数据结构,我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。然后我们每次取出最小的那个元素加入我们最终结果的链表中,然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可,代码如下:
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
auto cmp = [](ListNode*& a, ListNode*& b) {
return a->val > b->val;
};
priority_queue<ListNode*, vector<ListNode*>, decltype(cmp) > q(cmp);
for (auto node : lists) {
if (node) q.push(node);
}
ListNode *dummy = new ListNode(-1), *cur = dummy;
while (!q.empty()) {
auto t = q.top(); q.pop();
cur->next = t;
cur = cur->next;
if (cur->next) q.push(cur->next);
}
return dummy->next;
}
};
合并K个排序链表的思路来自:[LeetCode] Merge k Sorted Lists 合并k个有序链表 ,其中还列举许多种解法,可自行查阅.