模板题目链接
Lintcode 454. Sort Array : 归并排序
Leetcode 23. Merge K sort-lists : K路归并问题
归并排序思路
归并思路很好理解,以两个数组归并来举例,开一个新数组来保存新的合并结果,两个原始数组(需要保证两个原始数组有序)从头开始比较,哪个比较小就加入合并数组中,最后就是排序后结果。
对于归并排序问题,由于原始数组非有序,所以需要利用分治思想将原始数组分解到有序数组,也就是单一元素数组自身是有序,通过合并小问题来最终解决两个原始数组合并问题。
代码思路如下:
private int[] merge(int[] A, int st, int ed) {
// merge sort
if(st==ed) return new int[]{A[st]};
int mid = st + (ed-st>>1);
int[] left = merge(A, st, mid);
int[] right = merge(A, mid+1, ed);
// 同向双指针
int i = 0;
int i1 = 0;
int i2 = 0;
int n = left.length;
int m = right.length;
int[] res = new int[m+n];
while(i1<n && i2<m) {
if(left[i1]<=right[i2]) res[i++] = left[i1++];
else res[i++] = right[i2++];
}
while(i1<n) res[i++] = left[i1++];
while(i2<m) res[i++] = right[i2++];
return res;
}
时间复杂度:,
深度分治递归,每一次归并的时间是
;空间复杂度:
。
K路归并思路
K路归并通常可以解决一些大数据分布式排序问题(以及对于内存有限制的多路排序问题),并且由于各个服务器端的数据量很大无法全部写入同一个机器内存中进行排序时,我们可以利用k路归并来求解,具体思路就是根据数组个数,维护一个包含k个元素的小顶堆,小顶堆中每一个值就是各路的目前头一个元素,当某一路的元素从栈顶弹出,我们就从那一路数据流中接着读取下一个元素,直到数据流结束。
代码如下:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
// heap
PriorityQueue<Node> heap = new PriorityQueue<>((Node x, Node y) -> x.val-y.val);
for(int i=0; i<lists.length; i++) {
if(lists[i]==null) continue;
Node node = new Node(lists[i].val, i);
lists[i] = lists[i].next;
heap.offer(node);
}
ListNode res = new ListNode(-1);
ListNode curr = res;
while(!heap.isEmpty()) {
Node n = heap.poll();
ListNode newNode = new ListNode(n.val);
curr.next = newNode;
curr = curr.next;
if(lists[n.idx]!=null) {
Node v = new Node(lists[n.idx].val, n.idx);
heap.offer(v);
lists[n.idx] = lists[n.idx].next;
}
}
return res.next;
}
}
时间复杂度:, N是所有数组元素总和,k是小顶堆大小;空间复杂度:
,开一个新空间存储排序结果,以及小顶堆的空间。