文章均爲本人技術筆記,轉載請註明出處:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/java
歸併排序思想:歸併排序可用分治法實現,先保證局部有序,而後二路歸併局部有序部分爲總體有序;算法
lintcode Sort IntegersⅡsegmentfault
/** * 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]; } } }
class Solution { public int[] mergeSortedArray(int[] A, int[] B) { if (A == null || B == null) { return new int[0]; } ArrayList<Integer> 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; } }
lintcode Merge Sorted ArrayⅡ,與lintcode Merge Two Sorted ArraysⅠ相比,要求不使用額外空間;this
/** * 合併兩個有序數組,雙指針法二路歸併算法,最後覆蓋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<Integer> 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); } } }
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; } }
假定k路數組全爲升序數組,元素總數爲n,code
解法1:兩兩二路歸併O(n*k)實現
對k路數組兩兩進行二路歸併,時間複雜度高;blog
解法2:分治法O(nlogk)實現
分治思想自底向上,逐層二路歸併,遞歸空間爲O(logk),逐層二路歸併時間複雜度O(n);排序
解法3:最小堆O(nlogk)實現
用最小堆維護k路數組or鏈表的當前元素,問題轉換爲求k個數的最小值,堆頂出堆後將堆頂所在部分的下一個元素(若是存在你在)加入堆中,歸併過程當中訪問堆k次,每次訪問offer
或poll
的開銷爲O(log k);
/** * 解法1:逐個合併數組,時間複雜度O(n*k),n >> k * 合併k個排序(升序)數組 * http://www.lintcode.com/zh-cn/problem/merge-k-sorted-arrays/ * @author yzwall */ class Solution { public List<Integer> mergekSortedArrays(int[][] arrays) { ArrayList<Integer> list = new ArrayList<Integer>(); 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<Integer> mergekSortedArrays(int[][] arrays) { ArrayList<Integer> list = new ArrayList<Integer>(); 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<Integer> mergekSortedArrays(int[][] arrays) { ArrayList<Integer> list = new ArrayList<Integer>(); if (arrays == null || arrays.length == 0 || arrays[0].length == 0) { return list; } PriorityQueue<NewInteger> pq = new PriorityQueue<>(arrays.length, new Comparator<NewInteger>() { 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<Integer> mergekSortedArrays(int[][] arrays) { ArrayList<Integer> list = new ArrayList<Integer>(); 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(ArrayList<Integer>list, int[] nums) { for (int num : nums) { list.add(num); } } }
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<ListNode> lists) { if (lists == null || lists.size() == 0) { return null; } PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.size(), new Comparator<ListNode>() { 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<ListNode> lists) { if (lists == null || lists.size() == 0) { return null; } return kMergeSort(lists, 0, lists.size() - 1); } private ListNode kMergeSort(List<ListNode> 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; } }