Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
private Comparator<ListNode> listComparator = new Comparator<ListNode>(){
算法:
1. 用heap(priorityQueue)。维护一个最小堆,记录每一串ListNode当前指着的那k个(或者更少)ListNode,每次取出来直接是最小的那个。然后把取出来的这个后面的加回heap里。 每次取出小的后就可以直接连到长串上面了。
2.自上向下的类似mergeSort的分治法。写一个分治,每次把合并任务分成合并左边一半与合并右边一半,这是分。再重写一遍原来的merge two lists,这是合,类似于原来的merge。递归调用就好了。
3.自下而上的归并法。从一共k条链表开始,从左到右一条条两两合并,最后落单的话不合并,把这些新的链表作为向上一层的新的要处理的链表点。一直向上一直向上,直到合并成只有一个点的一条就可以输出了。
时间复杂度:都是Nlogk。N是所有节点个数,k是有链表条数。堆的话因为堆的深度是logK。分治法和归并法的话是因为长出来的树高度是logK。
细节: 1.用heap的话要实现Comparator<ListNode>。实现的写法多看几次下面的。实现细节太多了
a)记得写完内部类后要加;(因为前面是在赋值)
b)记得实现内部类的时候<>里不可以省略。
c)记得compare()这个方法全小写
d)记得return回去的int按传入参数顺序顺着来就是维护从小到大的堆。
e)记得初始化heap的时候可以传入两个参数,第一个大小,第二个比较器。大小的值必须>=1!Queue<ListNode> heap = new PriorityQueue<ListNode>(lists.length, listComparator);
f)heap不可以add(null)
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { // 切记前面等号右边<>里不可以省略,然后最后要加个分号 private Comparator<ListNode> listComparator = new Comparator<ListNode>(){ // 切记方法名都是小写 public int compare(ListNode l1, ListNode l2) { return l1.val - l2.val; } }; public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } ListNode dummy = new ListNode(0); ListNode prev = dummy; // 注意,java API里面要求初始化大小不能<1。所以要注意对lists.length = 0 的情况限定 Queue<ListNode> heap = new PriorityQueue<ListNode>(lists.length, listComparator); for (int i = 0; i < lists.length; i++) { // heap不能add(null) if (lists[i] != null) { heap.add(lists[i]); } } while (!heap.isEmpty()) { ListNode crt = heap.remove(); if (crt.next != null) { heap.add(crt.next); } prev.next = crt; prev = prev.next; } return dummy.next; } }
2.分治法
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } return recursiveHelper(lists, 0, lists.length - 1); } private ListNode recursiveHelper(ListNode[] lists, int start, int end) { if (start == end) { return lists[start]; } int mid = start + (end - start) / 2; ListNode left = recursiveHelper(lists, start, mid); ListNode right = recursiveHelper(lists, mid + 1, end); return merge2List(left, right); } private ListNode merge2List(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode prev = dummy; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { prev.next = l1; l1 = l1.next; } else { prev.next = l2; l2 = l2.next; } prev = prev.next; } if (l1 != null) { prev.next = l1; } if (l2 != null) { prev.next = l2; } return dummy.next; } }
3.归并法
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } List<ListNode> list = new ArrayList<>(); for (int i = 0; i < lists.length; i++) { if (lists[i] != null) { list.add(lists[i]); } } if (list.size() == 0) { return null; } while (list.size() > 1) { List<ListNode> newList = new ArrayList<>(); for (int i = 0; i + 1 < list.size(); i += 2) { newList.add(merge2List(list.get(i), list.get(i + 1))); } if (list.size() % 2 == 1) { newList.add(list.get(list.size() - 1)); } list = newList; } return list.get(0); } private ListNode merge2List(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode prev = dummy; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { prev.next = l1; l1 = l1.next; } else { prev.next = l2; l2 = l2.next; } prev = prev.next; } if (l1 != null) { prev.next = l1; } if (l2 != null) { prev.next = l2; } return dummy.next; } }