Merge Sorted Array
原题链接Merge Sorted Array
意思是给定两个有序数组,将其合并成一个有序数组,存在nums1中。
如果先只是简单合并成一个新数组,然后将新数组赋值给nums1,基本就算完成了。现在考虑不适用其它内存空间,在nums1上原地合并新数组。
遇到的问题是如果nums1[i] > nums2[j],那么nums1[i]的位置就应该被赋值给nums2[j],可是nums1[i]原先的值应该放在哪里呢,接下来还有用这个nums1[i]和nums2[j+1]继续比较呢。如果nums1[i]一直大于nums2[j],那么所有的nums1[i]又应该放在哪里呢。
方法是在开始合并前就给nums1的前面留出n个大小的空间,而把nums1原来的数据全移动到后面的位置(这里是移动到nums1[n : m+n)),这样,即使nums2全都小于nums1,nums2也可以原封不动的放进nums1中,并且不需要移动nums1原有的数据
0 1 2 3 4 5 下标
1 3 5 nums1
2 4 6 nums2
初始时
0 1 2 3 4 5 下标
1 3 5 nums1
2 4 6 nums2
开始合并
0 1 2 3 4 5 下标
1 1 3 5 nums1
2 4 6 nums2
------------------------------
1 2 1 3 5 nums1
2 4 6 nums2
------------------------------
1 2 3 1 3 5 nums1
2 4 6 nums2
------------------------------
1 2 3 4 3 5 nums1
2 4 6 nums2
------------------------------
1 2 3 4 5 5 nums1
2 4 6 nums2
------------------------------
1 2 3 4 5 6 nums1
2 4 6 nums2
------------------------------
合并完成
因为初始时nums1前面已经留有n个大小的空间(nums2的大小),所以在给nums1[0 : m+1)赋值时覆盖的都是合并完成,被放到前面的数据,不会丢失数据
代码如下
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for(int i = m - 1; i >= 0; --i)
nums1[i + n] = nums1[i];
int p1 = n;
int p2 = 0;
int idx = 0;
while(p1 < m + n && p2 < n)
{
nums1[idx++] = (nums1[p1] > nums2[p2]) ? nums2[p2++] : nums1[p1++];
}
while(p1 < m + n)
nums1[idx++] = nums1[p1++];
while(p2 < n)
nums1[idx++] = nums2[p2++];
}
};
Merge Two Sorted Lists
原题链接Merge Two Sorted Lists
意思是合并两个有序链表成为一个新的有序链表,比较简单,依次比较即可
细节方法是构造一个头节点,可以解决返回值是null的情况
/**
* 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* header = new ListNode(-1);
ListNode* cur = header;
while(l1 || l2)
{
int n = 0;
if(l1 == NULL || (l1 && l2 && l1->val > l2->val))
{
n = l2->val;
l2 = l2->next;
}
else if(l2 == NULL || (l1 && l2 && l1->val <= l2->val))
{
n = l1->val;
l1 = l1->next;
}
cur->next = new ListNode(n);
cur = cur->next;
}
ListNode *ans = header->next;
delete header;
return ans;
}
};
Merge k Sorted Lists
原题链接Merge k Sorted Lists
意思是合并k个有序链表,要求合成的链表也是有序的
两个链表时可以每次比较大小决定取哪个链表的值,k个就不能这么乱来了,不然复杂度会飙升。
可以维护一定大小的最小堆(优先级队列),堆中元素是ListNode类型,每次取最小的,然后插入取出的节点的下一个节点(如果是null就不用插入),直到堆变空为止。
需要注意的是如果ListNode设计时内部重载了operator<函数,那么直接创建优先级队列即可。但是题中给出的ListNode定义没有提供这样的函数,就需要自己实现,此时如果使用优先级队列的话,模板参数要提供三个
/**
* 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) {
if(lists.size() == 0)
return NULL;
/*
* 三个模板参数
* ListNode,存储的元素类型
* vector<ListNode>,内部存储方式,默认是vector,传入vector就好
* cmp,因为没有提供比较大小的函数,需要自己提供,但是不能简单的创建一个函数,需要一个函数对象(行为像函数的类),即重载了operator()的类
*/
std::priority_queue<ListNode, vector<ListNode>, cmp> pq;
for(auto node : lists)
{
if(node != NULL)
pq.push(std::move(*node));
}
ListNode* header = new ListNode(-1);
ListNode* cur = header;
while(pq.size() > 0)
{
ListNode node = pq.top();
pq.pop();
cur->next = new ListNode(node.val);
cur = cur->next;
if(node.next)
pq.push(std::move(*node.next));
}
ListNode* ans = header->next;
delete header;
return ans;
}
private:
struct cmp
{
/*
* 如果是增序,就判断是否大于
* 如果是减序,就判断是否小于
* 真怪...
*/
bool operator()(const ListNode& lhs, const ListNode& rhs)
{
return lhs.val > rhs.val;
}
};
};