剑指 Offer 41. 数据流中的中位数

和力扣295. 数据流的中位数 一致
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:

  • void addNum(int num) - 从数据流中添加一个整数到数据结构中。
  • double findMedian() - 返回目前所有元素的中位数。

**

完美的面试回答,你被录取了:

  • 在数据流中,数据会不断涌入结构中,那么也就面临着需要多次动态调整以获得中位数。 因此实现的数据结构需要既需要快速找到中位数,也需要做到快速调整。
  • 首先能想到就是二叉搜索树,在平衡状态下,树顶必定是中间数,然后再根据长度的奇偶性决定是否取两个数。
  • 此方法效率高,但是手动编写较费时费力。
  • 根据只需获得中间数的想法,可以将数据分为左右两边,一边以最大堆的形式实现,可以快速获得左侧最大数, 另一边则以最小堆的形式实现。其中需要注意的一点就是左右侧数据的长度差不能超过1。 这种实现方式的效率与AVL平衡二叉搜索树的效率相近,但编写更快
  1. // 两个堆-大顶~小顶 ;用队列建堆
  2. //时间:删除logn,查找O1;空间On
  3. type MedianFinder struct {
  4. heapMax *IntHeap1 // 最大堆 -> 代表排序后数据流的左半部分
  5. heapMin *IntHeap2 // 最小堆 -> 代表排序后数据流的右半部分
  6. }
  7. func Constructor() MedianFinder {
  8. return MedianFinder{heapMin: &IntHeap2{}, heapMax: &IntHeap1{}}
  9. }
  10. func (this *MedianFinder) AddNum(num int) {
  11. if (*this.heapMax).Len() == 0 {
  12. heap.Push(this.heapMax, num)
  13. return
  14. }
  15. m, n := (*this.heapMax).Len(), (*this.heapMin).Len()
  16. if m == n+1 {
  17. //1, 因为数据流的长度可能为奇数,所以允许最大堆的数量比最小堆的数量多1
  18. for num < (*this.heapMax)[0] {
  19. heap.Push(this.heapMax, num)
  20. num = heap.Pop(this.heapMax).(int)
  21. }
  22. //2, 最大堆的数量已经比最小堆多1,所以num应该加入最小堆
  23. heap.Push(this.heapMin, num)
  24. } else {
  25. for num > (*this.heapMin)[0] {
  26. heap.Push(this.heapMin, num)
  27. num = heap.Pop(this.heapMin).(int)
  28. }
  29. //3, 加入最大堆
  30. heap.Push(this.heapMax, num)
  31. }
  32. }
  33. func (this *MedianFinder) FindMedian() float64 {
  34. m, n := (*this.heapMax).Len(), (*this.heapMin).Len()
  35. if m == n { // 如果列表长度是偶数,中位数则是中间两个数的平均值。
  36. return (float64((*this.heapMax)[0]) + float64((*this.heapMin)[0])) / 2.0
  37. }
  38. return float64((*this.heapMax)[0])
  39. }
  40. // 最小堆
  41. type IntHeap2 []int
  42. func (h IntHeap2) Len() int { return len(h) }
  43. func (h IntHeap2) Less(i, j int) bool { return h[i] < h[j] } // 就这里不同
  44. func (h IntHeap2) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
  45. func (h *IntHeap2) Push(x interface{}) {
  46. *h = append(*h, x.(int))
  47. }
  48. func (h *IntHeap2) Pop() interface{} {
  49. old := *h
  50. n := len(old)
  51. x := old[n-1]
  52. *h = old[0 : n-1]
  53. return x
  54. }
  55. // 最大堆
  56. type IntHeap1 []int
  57. func (h IntHeap1) Len() int { return len(h) }
  58. func (h IntHeap1) Less(i, j int) bool { return h[i] > h[j] }
  59. func (h IntHeap1) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
  60. func (h *IntHeap1) Push(x interface{}) {
  61. *h = append(*h, x.(int))
  62. }
  63. func (h *IntHeap1) Pop() interface{} {
  64. old := *h
  65. n := len(old)
  66. x := old[n-1]
  67. *h = old[0 : n-1]
  68. return x
  69. }