Skip to content

Commit

Permalink
Merge 1613c37 into acba171
Browse files Browse the repository at this point in the history
  • Loading branch information
vaskoz committed Aug 27, 2018
2 parents acba171 + 1613c37 commit c9a57dd
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
86 changes: 86 additions & 0 deletions mergeKSortedLists/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package mergeklist

import (
"container/heap"
"math"
)

// MergeKSortedLists merges K-sorted lists into a single list
// Runtime is O(K*(K*N)) = O(K^2*N) assuming each list of is length N
// Space is O(K) for the indicies without considering the answer list of O(K*N) size.
// Use this if K is very small
func MergeKSortedLists(lists [][]int) []int {
idxs := make([]int64, len(lists))
var result []int
hasMore := true
for hasMore {
listID := -1
smallest := math.MaxInt64
// find the smallest next value
for i, idx := range idxs {
if idx < int64(len(lists[i])) && lists[i][idx] < smallest {
smallest = lists[i][idx]
listID = i
}
}
if listID == -1 {
hasMore = false
} else {
result = append(result, smallest)
idxs[listID]++
}
}
return result
}

type tuple struct {
id, pos, value int
}

type priorityQueue []*tuple

func (pq priorityQueue) Len() int { return len(pq) }

func (pq priorityQueue) Less(i, j int) bool {
return pq[i].value < pq[j].value
}

func (pq priorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}

func (pq *priorityQueue) Push(x interface{}) {
item := x.(*tuple)
*pq = append(*pq, item)
}

func (pq *priorityQueue) Pop() interface{} {
old := *pq
n := len(old)
tuple := old[n-1]
*pq = old[0 : n-1]
return tuple
}

// MergeKSortedListsUsingHeap merges K-sorted lists into a single list using a min-heap.
// Runtime is O(N*K log K) assuming each list of is length N
// Space is O(K) for the heap without considering the answer list of O(K*N) size.
// Use this if K is very large.
func MergeKSortedListsUsingHeap(lists [][]int) []int {
pq := make(priorityQueue, len(lists))
for i, lst := range lists {
pq[i] = &tuple{id: i, pos: 0, value: lst[0]}
}
heap.Init(&pq)
var result []int
for pq.Len() > 0 {
tup := heap.Pop(&pq).(*tuple)
result = append(result, tup.value)
id := tup.id
nextpos := tup.pos + 1
if nextpos < len(lists[id]) {
heap.Push(&pq, &tuple{id: id, pos: nextpos, value: lists[id][nextpos]})
}
}
return result
}
67 changes: 67 additions & 0 deletions mergeKSortedLists/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package mergeklist

import (
"reflect"
"testing"
)

var testcases = []struct {
input [][]int
expected []int
}{
{[][]int{
[]int{10, 15, 30},
[]int{12, 15, 20},
[]int{17, 20, 32}},
[]int{10, 12, 15, 15, 17, 20, 20, 30, 32}},
{[][]int{
[]int{1, 2, 3},
[]int{2, 4, 6},
[]int{1, 2, 3},
[]int{2, 5, 7}},
[]int{1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 7}},
{[][]int{
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},
[]int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}},
}

func TestMergeKSortedLists(t *testing.T) {
for i, tc := range testcases {
if result := MergeKSortedLists(tc.input); !reflect.DeepEqual(result, tc.expected) {
t.Errorf("did not merge list correctly for testcase#%d, got %v", i, result)
}
}
}

func BenchmarkMergeKSortedLists(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
MergeKSortedLists(tc.input)
}
}
}

func TestMergeKSortedListsUsingHeap(t *testing.T) {
for i, tc := range testcases {
if result := MergeKSortedListsUsingHeap(tc.input); !reflect.DeepEqual(result, tc.expected) {
t.Errorf("did not merge list correctly for testcase#%d, got %v", i, result)
}
}
}

func BenchmarkMergeKSortedListsUsingHeap(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
MergeKSortedListsUsingHeap(tc.input)
}
}
}

0 comments on commit c9a57dd

Please sign in to comment.