剑指OFFER----41、数据流中的中位数(js实现)

博客围绕如何得到数据流中的中位数展开。给出了LeetCode题目链接,解题思路是维护大顶堆和小顶堆。插入奇数个数时先放小顶堆再转大顶堆,偶数个数则相反。根据大小顶堆个数关系获取中位数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

  • 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有值排序之后位于中间的数值。如果数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
  • leetcode链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/

思路

  • 维护一个大顶堆,一个小顶堆
  • 插入奇数个的数,就先放到小顶堆,堆化之后再取出堆顶元素,插入到大顶堆中再堆化
  • 插入偶数个的数,就先放到大顶堆,堆化之后再取出堆顶元素,插入到小顶堆中再堆化
  • 大小顶堆个数相等时,分别拿堆顶元素再平分,如果个数不想等,从大顶堆拿堆顶元素

代码

/**
 * initialize your data structure here.
 */
var MedianFinder = function () {
  this.smallHeap = new SmallHeap()
  this.bigHeap = new BigHeap()
}

/**
 * @param {number} num
 * @return {void}
 */
MedianFinder.prototype.addNum = function (num) {
  if (this.smallHeap.size() === this.bigHeap.size()) {
    this.smallHeap.insert(num)
    const p = this.smallHeap.pick()
    this.bigHeap.insert(p)
  } else {
    this.bigHeap.insert(num)
    const p = this.bigHeap.pick()
    this.smallHeap.insert(p)
  }
}

/**
 * @return {number}
 */
MedianFinder.prototype.findMedian = function () {
  if (this.smallHeap.size() === this.bigHeap.size()) {
    return (this.smallHeap.top() + this.bigHeap.top()) / 2
  } else {
    return this.bigHeap.top()
  }
}

class SmallHeap {
  constructor() {
    this.heap = [null]
  }
  top() {
    return this.heap[1]
  }
  size() {
    return this.heap.slice(1).length
  }
  getHeap() {
    return this.heap.slice(1)
  }
  insert(x) {
    this.heap.push(x)
    let index = this.heap.length - 1
    while (
      Math.floor(index / 2) > 0 &&
      this.heap[Math.floor(index / 2)] > this.heap[index]
    ) {
      swap(this.heap, Math.floor(index / 2), index)
      index = Math.floor(index / 2)
    }
  }
  pick() {
    if (this.size()) {
      swap(this.heap, 1, this.heap.length - 1)
      const p = this.heap.pop()
      this.heapify()
      return p
    }
  }
  heapify() {
    let i = 1
    while (i < this.heap.length) {
      let minIndex = i
      if (2 * i < this.heap.length && this.heap[2 * i] < this.heap[minIndex]) {
        minIndex = 2 * i
      }
      if (
        2 * i + 1 < this.heap.length &&
        this.heap[2 * i + 1] < this.heap[minIndex]
      ) {
        minIndex = 2 * i + 1
      }
      if (minIndex === i) break
      swap(this.heap, minIndex, i)
      i = minIndex
    }
  }
}

class BigHeap {
  constructor() {
    this.heap = [null]
  }
  top() {
    return this.heap[1]
  }
  size() {
    return this.heap.slice(1).length
  }
  getHeap() {
    return this.heap.slice(1)
  }
  insert(x) {
    this.heap.push(x)
    let index = this.heap.length - 1
    while (
      Math.floor(index / 2) > 0 &&
      this.heap[Math.floor(index / 2)] < this.heap[index]
    ) {
      swap(this.heap, Math.floor(index / 2), index)
      index = Math.floor(index / 2)
    }
  }
  pick() {
    if (this.size()) {
      swap(this.heap, 1, this.heap.length - 1)
      const p = this.heap.pop()
      this.heapify()
      return p
    }
  }
  heapify() {
    let i = 1
    while (i < this.heap.length) {
      let maxIndex = i
      if (2 * i < this.heap.length && this.heap[2 * i] > this.heap[maxIndex]) {
        maxIndex = 2 * i
      }
      if (
        2 * i + 1 < this.heap.length &&
        this.heap[2 * i + 1] > this.heap[maxIndex]
      ) {
        maxIndex = 2 * i + 1
      }
      if (maxIndex === i) break
      swap(this.heap, maxIndex, i)
      i = maxIndex
    }
  }
}

function swap(arr, i, j) {
  const temp = arr[i]
  arr[i] = arr[j]
  arr[j] = temp
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值