Leetcode1-100: 23. Merge k Sorted Lists
问题描述
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
题目要求是合并k个已经排序后的字符串。
解题思路
- 类似于brute force 吧,不过过程中还是需要一些操作来减少时间复杂度的。通过一个mask变量来看是否跳出循环,只有在只剩下一个非空子串的时候选择跳出循环。
- Priority Queue,使用优先队列来帮助实现入栈和出栈来减少时间复杂度。因为优先队列的出栈时间复杂度是O(log(k)),就不需要用线性时间来比较所有队首元素的大小了
- Divide and conquer,每次合并两个元素然后到下一级知道合并成一个元素
代码实现
implement 1 Brute force
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode dummy = new ListNode(-1), p = dummy;
while(true) {
int mask = 0, min = Integer.MAX_VALUE;
int candidate = -1;
for(int i = 0; i < lists.length; i++) {
if(lists[i] == null) mask++; //统计空串的数量
else {
if(lists[i].val < min) {
min = lists[i].val;
candidate = i;
}
}
}
if(mask == lists.length - 1) { //当前得到的最小值是最后一个值串
p.next = lists[candidate];
return dummy.next;
}
else if(mask == lists.length) {
return null;
}
else {
p.next = lists[candidate];
lists[candidate] = lists[candidate].next;
p = p.next;
}
}
}
复杂度分析:
时间复杂度:假设最长的链表长度是 n ,那么 while 循环将循环 n 次。
假设链表列表里有 k 个链表,for 循环执行 k 次,所以时间复杂度是 O(kn)
空间复杂度:O(1)(没有创建节点,直接改变链表的指向)
implement 2 Priority Queue
public ListNode mergeKLists(ListNode[] lists) {
Comparator<ListNode> cmp;
cmp = new Comparator<ListNode>() {
// 需要先定义比较器来帮助队列判断ListNode的大小关系
@Override
public int compare(ListNode o1, ListNode o2) {
// TODO Auto-generated method stub
return o1.val-o2.val;
}
};
Queue<ListNode> q = new PriorityQueue<ListNode>(cmp);
for(ListNode l : lists){
if(l!=null){
q.add(l);
}
}
ListNode head = new ListNode(0);
ListNode point = head;
while(!q.isEmpty()){
//出队列一个元素
point.next = q.poll();
point = point.next;
ListNode next = point.next;
将新元素加进队列
if(next!=null){
q.add(next);
}
}
return head.next;
}
复杂度分析:
时间复杂度:假如总共有 N 个节点,每个节点入队出队都需要 log(k),
所有时间复杂度是 O(N log(k))
空间复杂度:优先队列需要 O(k)的复杂度
implement 3. Divide and conquer
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode h = new ListNode(0);
ListNode ans=h;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
h.next = l1;
h = h.next;
l1 = l1.next;
} else {
h.next = l2;
h = h.next;
l2 = l2.next;
}
}
if(l1==null){
h.next=l2;
}
if(l2==null){
h.next=l1;
}
return ans.next;
}
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0){
return null;
}
int interval = 1;
while(interval<lists.length){
System.out.println(lists.length);
for (int i = 0; i + interval< lists.length; i=i+interval*2) {
lists[i]=mergeTwoLists(lists[i],lists[i+interval]);
}
interval*=2;
}
return lists[0];
}
复杂度分析:
时间复杂度:假设每个链表的长度都是 n ,有 k 个链表,记总结点数是 N = n * k.
那么时间复杂度就是O(Nlogk)
空间复杂度:O(1)
分析
这题的方法有很多,甚至leetcode的solution给出第一个brute force是把所有元素直接放到一个数组里面然后再排序。
后面两种实现就没有自己写,参考了一下评论里面大佬们的解法粘上去了,大家有兴趣的可以去看看。