23. 合并K个排序链表-H

23. 合并K个排序链表-H

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6

  • 分析
    这道题合并有序链表,主要是看复杂度,假设k个链表,每个链表n个元素,各方法有:
  1. 暴力,从头到位合并,复杂度O(nk^2)runtime,O(1)space
  2. 堆方法,构建k大小的堆,依次读取,插入、退出堆;复杂度O(nk*logk)runtime,O(1)space,见code2
  3. 通过调整方法1的合并顺序,现在通过两两合并的方式,有公式推导得出,复杂度O(nklogk)runtime,O(1)space
  • code3
/**
我的提交执行用时
已经战胜 100.00 % 的 golang 提交记录
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func merge(a,b *ListNode)*ListNode{
    head:=&ListNode{0,nil};p:=head
    for a!=nil&&b!=nil{
        if a.Val>b.Val{
            p.Next=b;p=p.Next
            b=b.Next
        }else{
            p.Next=a;p=p.Next
            a=a.Next
        }
    }
    if a!=nil{
        p.Next=a
    }
    if b!=nil{
        p.Next=b
    }
    return head.Next
    
}
func mergeKLists(lists []*ListNode) *ListNode {
    i:=0;s:=len(lists)
    if s==0{
        return nil
    }
    for s>1{
        for j:=0;j<s;j+=2{
            if j+1<s{
                lists[i]=merge(lists[j],lists[j+1])
            }else{
                lists[i]=lists[j]
            }
            i++
        }
        s=s-s/2;i=0
    }
    return lists[0]
}
  • code2
package main
import (
	"container/heap"
	"fmt"
)
 type ListNode struct {
     Val int
     Next *ListNode
 }
type Item struct {
	value    *ListNode// 改成自己需要的结构
	priority int    // The priority of the item in the queue.
	index int // The index of the item in the heap.
}
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].value.Val< pq[j].value.Val//改成大顶堆,让弹出的顺序是非递减
}
func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	item.index = -1 // for safety
	*pq = old[0 : n-1]
	return item
}
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists)==0{
		return nil
	}
	//空的不能进入到heap中
	pq := make(PriorityQueue, len(lists))
	c:=0
	for _,b:=range lists{
		if b!=nil{
			pq[c]=&Item{
				b,
				0,//这个改成0就行,因为不需要优先级,堆顶元素就是最值
				0,
			}
			c++
		}else{
			pq=pq[:len(pq)-1]
			//有[[nil]]的测试用例,注意控制,不能写入nil,否则堆中swap会交换nil时,崩溃
		}
	}
	heap.Init(&pq)
	head:=&ListNode{0,nil};p:=head
	for pq.Len() > 0 {
		pitem := heap.Pop(&pq)
		if pitem==nil{
			continue
		}
		item := pitem.(*Item)
		if item.value==nil{
			continue
		}
		p.Next=item.value
		p=p.Next
		if item.value.Next!=nil{
			heap.Push(&pq,&Item{item.value.Next,0,0})
		}
	}
	return head.Next
}
func main() {
	lists := []*ListNode{
		&ListNode{1, &ListNode{2, &ListNode{5,nil}}},
		&ListNode{4, &ListNode{5, &ListNode{6,nil}}},
		&ListNode{2, &ListNode{6, nil}},
	}
	//lists=[]*ListNode{nil}
	head:=mergeKLists(lists)
	for head!=nil{
		fmt.Println(head.Val)
		head=head.Next
	}
}
  • code1
/**
执行用时: 152 ms, 在Merge k Sorted Lists的Go提交中击败了34.81% 的用户
内存消耗: 5.5 MB, 在Merge k Sorted Lists的Go提交中击败了18.42% 的用户
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func merge(a,b *ListNode)*ListNode{
    head:=&ListNode{0,nil};p:=head
    for a!=nil&&b!=nil{
        if a.Val>b.Val{
            p.Next=b;p=p.Next
            b=b.Next
        }else{
            p.Next=a;p=p.Next
            a=a.Next
        }
    }
    if a!=nil{
        p.Next=a
    }
    if b!=nil{
        p.Next=b
    }
    return head.Next
    
}
func mergeKLists(lists []*ListNode) *ListNode {
    s:=len(lists)
    if s==0{
        return nil
    }
    for i:=1;i<s;i++{
        lists[0]=merge(lists[0],lists[i])
    }
    return lists[0]
}

你可能感兴趣的:(23. 合并K个排序链表-H)