K路归并问题小结
声明
文章均为本人技术笔记,转载请注明出处:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/
1 二路归并
1.1 归并排序-数组
归并排序思想:归并排序可用分治法实现,先保证局部有序,然后二路归并局部有序部分为整体有序;
lintcode Sort IntegersⅡ
/**
* http://www.lintcode.com/en/problem/sort-integers-ii/
* 归并排序一个整型数组(升序)
* @author yzwall
*/
class Solution {
public void sortIntegers2(int[] A) {
if (A == null || A.length == 0) {
return;
}
mergeSort(A, 0, A.length - 1);
}
// 分治递归空间O(logn),逐层合并时间复杂度O(n)
private void mergeSort(int[] A, int start, int end) {
if (start >= end) {
return;
}
int mid = start + (end - start) / 2;
mergeSort(A, start, mid);
mergeSort(A, mid + 1, end);
mergeTwoArrays(A, start, end);
}
// 二路归并时间复杂度O(n),空间复杂度O(n)
private void mergeTwoArrays(int[] A, int start, int end) {
int mid = start + (end - start) / 2;
int i = start, j = mid + 1;
int index = 0;
int[] temp = new int[end - start + 1];
while (i <= mid && j <= end) {
if (A[i] < A[j]) {
temp[index++] = A[i++];
} else {
temp[index++] = A[j++];
}
}
while (i <= mid) {
temp[index++] = A[i++];
}
while (j <= end) {
temp[index++] = A[j++];
}
for (int k = 0; k < index; k++) {
A[start + k] = temp[k];
}
}
}
1.2 合并两个排序数组
lintcode Merge Two Sorted ArraysⅠ
class Solution {
public int[] mergeSortedArray(int[] A, int[] B) {
if (A == null || B == null) {
return new int[0];
}
ArrayList list = new ArrayList<>();
int i = 0, j = 0;
while (i < A.length && j < B.length) {
if (A[i] <= B[j]) {
list.add(A[i]);
i++;
} else {
list.add(B[j]);
j++;
}
}
while (i < A.length) {
list.add(A[i++]);
}
while (j < B.length) {
list.add(B[j++]);
}
int[] results = new int[list.size()];
for (i = 0; i < list.size(); i++) {
results[i] = list.get(i);
}
return results;
}
}
1.2 合并两个排序数组
lintcode Merge Sorted ArrayⅡ,与lintcode Merge Two Sorted ArraysⅠ相比,要求不使用额外空间;
/**
* 合并两个有序数组,双指针法二路归并算法,最后覆盖A数组
* http://www.lintcode.com/zh-cn/problem/merge-sorted-array/
* @author yzwall
*/
class Solution {
public void mergeSortedArray(int[] A, int m, int[] B, int n) {
int i = 0, j = 0;
ArrayList list = new ArrayList<>();
while (i < m && j < n) {
if (A[i] <= B[j]) {
list.add(A[i]);
i++;
} else {
list.add(B[j]);
j++;
}
}
while (i < m) {
list.add(A[i++]);
}
while (j < n) {
list.add(B[j++]);
}
for (int k = 0; k < list.size(); k++) {
A[k] = list.get(k);
}
}
}
1.3 合并两个排序链表
lintcode Merge Two Sorted Lists
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null && l2 == null) {
return null;
}
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
ListNode pIter1 = l1, pIter2 = l2;
ListNode head = new ListNode(-1);
ListNode pIter = head;
while (pIter1 != null && pIter2 != null) {
if (pIter1.val < pIter2.val) {
pIter.val = pIter1.val;
pIter1 = pIter1.next;
} else {
pIter.val = pIter2.val;
pIter2 = pIter2.next;
}
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
while (pIter1 != null) {
pIter.val = pIter1.val;
pIter1 = pIter1.next;
if (pIter1 != null) {
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
}
while (pIter2 != null) {
pIter.val = pIter2.val;
pIter2 = pIter2.next;
if (pIter2 != null) {
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
}
return head;
}
}
1.4 归并排序-链表
lintcode sort list
2 K路归并排序
2.1 K路归并算法实现小结
假定k路数组全为升序数组,元素总数为n,
解法1:两两二路归并O(n*k)实现
对k路数组两两进行二路归并,时间复杂度高;解法2:分治法O(nlogk)实现
分治思想自底向上,逐层二路归并,递归空间为O(logk),逐层二路归并时间复杂度O(n);解法3:最小堆O(nlogk)实现
用最小堆维护k路数组or链表的当前元素,问题转换为求k个数的最小值,堆顶出堆后将堆顶所在部分的下一个元素(如果存在你在)加入堆中,归并过程中访问堆k次,每次访问offer
或poll
的开销为O(log k);
2.2 K路归并数组多种解法实现
lintcode Merge K Sorted Arrays
/**
* 解法1:逐个合并数组,时间复杂度O(n*k),n >> k
* 合并k个排序(升序)数组
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-arrays/
* @author yzwall
*/
class Solution {
public List mergekSortedArrays(int[][] arrays) {
ArrayList list = new ArrayList();
if (arrays == null || arrays.length == 0 || arrays[0].length == 0) {
return list;
}
if (arrays.length == 1) {
Arrays.sort(arrays[0]);
for (int num : arrays[0]) {
list.add(num);
}
return list;
}
int[] temp = mergeTwoArrays(arrays[0], arrays[1]);
for (int i = 2; i < arrays.length; i++) {
temp = mergeTwoArrays(temp, arrays[i]);
}
for (int num : temp) {
list.add(num);
}
return list;
}
private int[] mergeTwoArrays(int[] A, int[] B) {
if (A.length == 0 || B.length == 0) {
return new int[0];
}
int[] temp = new int[A.length + B.length];
int index = 0, i = 0, j = 0;
while (i < A.length && j < B.length) {
if (A[i] < B[j]) {
temp[index++] = A[i++];
} else {
temp[index++] = B[j++];
}
}
while (i < A.length) {
temp[index++] = A[i++];
}
while (j < B.length) {
temp[index++] = B[j++];
}
return temp;
}
}
/**
* 解法2:分治法K路归并,时间复杂度O(n logk)
* 合并k个排序(升序)数组
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-arrays/
* @author yzwall
*/
class Solution20 {
public List mergekSortedArrays(int[][] arrays) {
ArrayList list = new ArrayList();
if (arrays == null || arrays.length == 0 || arrays[0].length == 0) {
return list;
}
int[] ans = kMergeSort(arrays, 0, arrays.length - 1);
for (int num : ans) {
list.add(num);
}
return list;
}
// 分治递归深度为O(log k), 每层合并时间复杂度O(n)
private int[] kMergeSort(int[][] arrays, int start, int end) {
if (start >= end) {
return arrays[start];
}
int mid = start + (end - start) / 2;
int[] left = kMergeSort(arrays, start, mid);
int[] right = kMergeSort(arrays, mid + 1, end);
return mergeTwoArrays(left, right);
}
private int[] mergeTwoArrays(int[] A, int[] B) {
int[] temp = new int[A.length + B.length];
int index = 0, i = 0, j = 0;
while (i < A.length && j < B.length) {
if (A[i] < B[j]) {
temp[index++] = A[i++];
} else {
temp[index++] = B[j++];
}
}
while (i < A.length) {
temp[index++] = A[i++];
}
while (j < B.length) {
temp[index++] = B[j++];
}
return temp;
}
}
/**
* 解法3:最小堆实现K路归并,时间复杂度O(n logk)
* 合并k个排序(升序)数组
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-arrays/
* @author yzwall
*/
class Solution18 {
private class NewInteger {
int value, row, col;
public NewInteger(int value, int row, int col) {
this.value = value;
this.row = row;
this.col = col;
}
}
public List mergekSortedArrays(int[][] arrays) {
ArrayList list = new ArrayList();
if (arrays == null || arrays.length == 0 || arrays[0].length == 0) {
return list;
}
PriorityQueue pq = new PriorityQueue<>(arrays.length, new Comparator() {
public int compare(NewInteger o1, NewInteger o2) {
return o1.value < o2.value ? -1 : 1;
}
});
for (int i = 0; i < arrays.length; i++) {
pq.offer(new NewInteger(arrays[i][0], i, 0));
}
while (!pq.isEmpty()) {
NewInteger min = pq.poll();
if (min.col + 1 < arrays[min.row].length) {
pq.offer(new NewInteger(arrays[min.row][min.col + 1], min.row, min.col + 1));
}
list.add(min.value);
}
return list;
}
}
/**
* 解法4:暴力方法,将所有数组添加到List,统一排序,时间复杂度O(n*k + nlogn), n >> k
* 合并k个排序(升序)数组
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-arrays/
* @author yzwall
*/
class Solution19 {
public List mergekSortedArrays(int[][] arrays) {
ArrayList list = new ArrayList();
if (arrays == null || arrays.length == 0 || arrays[0].length == 0) {
return list;
}
for (int i = 0; i < arrays.length; i++) {
addToList(list, arrays[i]);
}
Collections.sort(list);
return list;
}
private void addToList(ArrayListlist, int[] nums) {
for (int num : nums) {
list.add(num);
}
}
}
2.3 K路归并链表多种解法实现
lintcode Merge K Sorted Lists
/**
* 解法1:最小堆实现K路归并,时间复杂度O(nlogk)
* 合并K路排序链表
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-lists/
* @author yzwall
*/
class Solution {
public ListNode mergeKLists(List lists) {
if (lists == null || lists.size() == 0) {
return null;
}
PriorityQueue pq = new PriorityQueue<>(lists.size(), new Comparator() {
public int compare(ListNode o1, ListNode o2) {
return o1.val < o2.val ? -1 : 1;
}
});
for (ListNode head : lists) {
if (head != null) {
pq.offer(head);
}
}
ListNode head = new ListNode(-1);
ListNode pIter = head;
while (!pq.isEmpty()) {
ListNode min = pq.poll();
if (min.next != null) {
pq.offer(min.next);
}
ListNode pNew = new ListNode(min.val);
pIter.next = pNew;
pIter = pIter.next;
}
head = head.next;
return head;
}
}
/**
* 解法2:分治法K路归并
* 合并K路排序链表
* http://www.lintcode.com/zh-cn/problem/merge-k-sorted-lists/
* @author yzwall
*/
class Solution22 {
public ListNode mergeKLists(List lists) {
if (lists == null || lists.size() == 0) {
return null;
}
return kMergeSort(lists, 0, lists.size() - 1);
}
private ListNode kMergeSort(List lists, int start, int end) {
if (start >= end) {
return lists.get(start);
}
int mid = start + (end - start) / 2;
ListNode left = kMergeSort(lists, start, mid);
ListNode right = kMergeSort(lists, mid + 1, end);
return mergeTwoLists(left, right);
}
private ListNode mergeTwoLists(ListNode left, ListNode right) {
if (left == null) {
return right;
}
if (right == null) {
return left;
}
ListNode head = new ListNode(-1);
// pIter始终指向新节点
ListNode pIter = head;
ListNode p1 = left, p2 = right;
while (p1 != null && p2 != null) {
if (p1.val < p2.val) {
pIter.val = p1.val;
p1 = p1.next;
} else {
pIter.val = p2.val;
p2 = p2.next;
}
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
while (p1 != null) {
pIter.val = p1.val;
if (p1.next != null) {
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
p1 = p1.next;
}
while (p2 != null) {
pIter.val = p2.val;
if (p2.next != null) {
ListNode pNew = new ListNode(-1);
pIter.next = pNew;
pIter = pIter.next;
}
p2 = p2.next;
}
return head;
}
}