Introduction Link to heading
You’re given a list of n integers arr[0..(n-1)]. You must compute a list output[0..(n-1)] such that, for each index i (between 0 and n-1, inclusive), output[i] is equal to the median of the elements arr[0..i] (rounded down to the nearest integer).
The median of a list of integers is defined as follows. If the integers were to be sorted, then: If there are an odd number of integers, then the median is equal to the middle integer in the sorted order. Otherwise, if there are an even number of integers, then the median is equal to the average of the two middle-most integers in the sorted order.
Signature Link to heading
int[] findMedian(int[] arr)
Input
n is in the range [1, 1,000,000].
Each value arr[i] is in the range [1, 1,000,000].
Output
Return a list of n integers output[0..(n-1)], as described above.
Example 1
n = 4
arr = [5, 15, 1, 3]
output = [5, 10, 5, 4]
The median of [5] is 5, the median of [5, 15] is (5 + 15) / 2 = 10, the median of [5, 15, 1] is 5, and the median of [5, 15, 1, 3] is (3 + 5) / 2 = 4.
Example 2
n = 2
arr = [1, 2]
output = [1, 1]
The median of [1] is 1, the median of [1, 2] is (1 + 2) / 2 = 1.5 (which should be rounded down to 1).
Solution Link to heading
Let’s use two heaps: maxHeap for numbers less than median, minHeap for numbers greater than median. On each step we need to balance heaps in the way that first one have to be equal or greater one size of second one. Median is the top element on minHeap or if sizes are equal then average of top elements of both heaps.
package main
import (
"container/heap"
"encoding/json"
"fmt"
)
type MinHeap []int
func (h MinHeap) Len() int { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h MinHeap) Top() int { return h[0] }
func (h *MinHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *MinHeap) Pop() interface{} {
arr := *h
n := len(arr)
x := arr[n-1]
*h = arr[0 : n-1]
return x
}
type MaxHeap []int
func (h MaxHeap) Len() int { return len(h) }
func (h MaxHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h MaxHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h MaxHeap) Top() int { return h[0] }
func (h *MaxHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *MaxHeap) Pop() interface{} {
arr := *h
n := len(arr)
x := arr[n-1]
*h = arr[0 : n-1]
return x
}
func findMedian(arr []int) []int {
n := len(arr)
out := make([]int, n)
// lower elements
maxHeap := &MaxHeap{}
heap.Init(maxHeap)
// Higher elements
minHeap := &MinHeap{}
heap.Init(minHeap)
for i := 0; i < n; i++ {
if minHeap.Len() > 0 && minHeap.Top() < arr[i] {
heap.Push(minHeap, arr[i])
if maxHeap.Len()-1 < minHeap.Len() {
heap.Push(maxHeap, heap.Pop(minHeap))
}
} else {
heap.Push(maxHeap, arr[i])
if maxHeap.Len()-1 > minHeap.Len() {
heap.Push(minHeap, heap.Pop(maxHeap))
}
}
median := maxHeap.Top()
if maxHeap.Len() == minHeap.Len() {
median = ( median + minHeap.Top() ) / 2
}
out[i] = median
}
return out
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
arrStr := "[5, 15, 1, 3]"
var arr []int
json.Unmarshal([]byte(arrStr), &arr)
out := findMedian(arr)
fmt.Printf("actual = %v\n", out)
println("expected = [5, 10, 5, 4]")
arrStr = "[2, 4, 7, 1, 5, 3]"
json.Unmarshal([]byte(arrStr), &arr)
out = findMedian(arr)
fmt.Printf("actual = %v\n", out)
println("expected = [2, 3, 4, 3, 4, 3]")
}
Performance is good.