leetcode-295 Find Median from Data Stream

news2025/6/4 14:57:39
class MaxHeap {
  private heap: number[];
  constructor() {
    this.heap = [];
  }

  // 插入元素并上浮调整
  push(num: number): void {
    this.heap.push(num);
    this.siftUp(this.heap.length - 1);
  }

  // 弹出堆顶元素并下沉调整
  pop(): number {
    const top = this.heap[0];
    const last = this.heap.pop()!;
    if (this.heap.length > 0) {
      this.heap[0] = last;
      this.siftDown(0);
    }
    return top;
  }

  // 堆顶元素
  peek(): number {
    return this.heap[0];
  }

  size(): number {
    return this.heap.length;
  }

  // 上浮操作
  private siftUp(index: number): void {
    while (index > 0) {
      const parent = Math.floor((index - 1) / 2);
      if (this.heap[parent] >= this.heap[index]) break;
      [this.heap[parent], this.heap[index]] = [
        this.heap[index],
        this.heap[parent],
      ];
      index = parent;
    }
  }

  // 下沉操作
  private siftDown(index: number): void {
    const size = this.size();
    while (index < size) {
      let left = 2 * index + 1;
      let right = 2 * index + 2;
      let largest = index;
      if (left < size && this.heap[left] > this.heap[largest]) largest = left;
      if (right < size && this.heap[right] > this.heap[largest])
        largest = right;
      if (largest === index) break;
      [this.heap[index], this.heap[largest]] = [
        this.heap[largest],
        this.heap[index],
      ];
      index = largest;
    }
  }
}

class MinHeap {
  private heap: number[];
  constructor() {
    this.heap = [];
  }

  push(num: number): void {
    this.heap.push(num);
    this.siftUp(this.heap.length - 1);
  }

  pop(): number {
    const top = this.heap[0];
    const last = this.heap.pop()!;
    if (this.heap.length > 0) {
      this.heap[0] = last;
      this.siftDown(0);
    }
    return top;
  }

  peek(): number {
    return this.heap[0];
  }

  size(): number {
    return this.heap.length;
  }

  private siftUp(index: number): void {
    while (index > 0) {
      const parent = Math.floor((index - 1) / 2);
      if (this.heap[parent] <= this.heap[index]) break;
      [this.heap[parent], this.heap[index]] = [
        this.heap[index],
        this.heap[parent],
      ];
      index = parent;
    }
  }

  private siftDown(index: number): void {
    const size = this.size();
    while (index < size) {
      let left = 2 * index + 1;
      let right = 2 * index + 2;
      let smallest = index;
      if (left < size && this.heap[left] < this.heap[smallest]) smallest = left;
      if (right < size && this.heap[right] < this.heap[smallest])
        smallest = right;
      if (smallest === index) break;
      [this.heap[index], this.heap[smallest]] = [
        this.heap[smallest],
        this.heap[index],
      ];
      index = smallest;
    }
  }
}
class MedianFinder {
  private maxHeap: MaxHeap; // 较小的一半(最大堆)
  private minHeap: MinHeap; // 较大的一半(最小堆)

  constructor() {
    this.maxHeap = new MaxHeap();
    this.minHeap = new MinHeap();
  }

  addNum(num: number): void {
    // 优先插入最大堆
    this.maxHeap.push(num);
    // 将最大堆的堆顶移动到最小堆(确保最大堆堆顶 ≤ 最小堆堆顶)
    this.minHeap.push(this.maxHeap.pop());
    // 平衡堆大小,确保最大堆大小 >= 最小堆
    if (this.maxHeap.size() < this.minHeap.size()) {
      this.maxHeap.push(this.minHeap.pop());
    }
  }

  findMedian(): number {
    if (this.maxHeap.size() === this.minHeap.size()) {
      return (this.maxHeap.peek() + this.minHeap.peek()) / 2;
    } else {
      return this.maxHeap.peek();
    }
  }
}


//分块加载
function calculateExactMedian(data: number[], chunkSize: number) {
  const chunks = [];

  // 分块加载数据
  for (let i = 0; i < data.length; i += chunkSize) {
    const chunk = data.slice(i, i + chunkSize);
    chunks.push(chunk);
  }

  // 对每个小块进行排序
  const sortedChunks = chunks.map((chunk) => chunk.sort((a, b) => a - b));

  // 合并所有排序后的块
  const mergedArray = [];
  sortedChunks.forEach((chunk) => {
    mergedArray.push(...chunk);
  });

  // 对合并后的数组进行排序
  mergedArray.sort((a, b) => a - b);

  // 计算中位数
  const length = mergedArray.length;
  if (length % 2 === 0) {
    return (mergedArray[length / 2 - 1] + mergedArray[length / 2]) / 2;
  } else {
    return mergedArray[Math.floor(length / 2)];
  }
}



//测试中位数计算效率
const nums: number[] = [];
const len = 10 ** 7;
for (let i = 0; i < len; i++) {
  nums.push(Math.floor(Math.random() * 100));
}

const $s = performance.now();
const medianFinder = new MedianFinder();
for (let i = 0; i < nums.length; i++) {
  medianFinder.addNum(nums[i]);
}
console.log(medianFinder.findMedian()); // 输出中位数
const $e = performance.now();
console.log($e - $s, '@heap_sort');

//使用普通数组的方式
const $s1 = performance.now();
nums.sort((a, b) => a - b); // 排序
const n = nums.length;
if (n % 2 === 0) {
  console.log((nums[n / 2 - 1] + nums[n / 2]) / 2); // 偶数个元素,取中间两个的平均值
} else {
  console.log(nums[Math.floor(n / 2)]); // 奇数个元素,取中间的元素}
}
const $e1 = performance.now();
console.log($e1 - $s1, '@arr_sort');

// 设置块大小
const $s2 = performance.now();
const chunkSize = 10000;
console.log(calculateExactMedian(nums, chunkSize));
const $e2 = performance.now();
console.log($e2 - $s2, '@chunk_sort');

output:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386797.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【后端高阶面经:缓存篇】37、高并发系统缓存性能优化:从本地到分布式的全链路设计

一、缓存性能优化的核心价值与分层架构 (一)缓存的多维价值体系 延迟优化 内存访问速度(100ns) vs 磁盘数据库(10ms+),性能提升10万倍+案例:电商详情页通过缓存将响应时间从500ms降至50ms吞吐提升 单机Redis可支撑10万QPS,分担数据库压力案例:秒杀系统通过缓存拦截9…

欣佰特科技| SIL2/PLd 认证 Inxpect毫米波安全雷达:3D 扫描 + 微小运动检测守护工业安全

Inxpect 成立于意大利&#xff0c;专注工业安全技术。自成立起&#xff0c;便致力于借助先进雷达技术提升工业自动化安全标准&#xff0c;解决传统安全设备在复杂环境中的局限&#xff0c;推出获 SIL2/PLd 和 UL 认证的安全雷达产品。 Inxpect 的雷达传感器技术优势明显。相较于…

【Linux】Linux 操作系统 - 18 , 重谈文件(二) ~ 文件描述符和重定向原理 , 手把手带你彻底理解 !!!

文章目录 ● 文件描述符一 、Linux 系统对文件的管理(要知道)二 、什么是文件描述符 fd ?三 、再探文件被管理过程(重要)四 、文件描述符 0 、1、21. 文件描述符的分配原则2. 提前认识三个默认打开的文件 ● 重定向原理(重要)一 、重定向现象二 、深入剖析重定向现象(重要)1…

第五十三节:综合项目实践-车牌识别系统

一、项目背景与意义 车牌识别系统(LPR)是智能交通领域的核心技术之一,广泛应用于停车场管理、违章抓拍、高速公路收费等场景。本文将通过Python+OpenCV实现一个完整的车牌识别系统,涵盖图像预处理→车牌定位→字符分割→字符识别四大核心环节。 二、系统架构设计 技术栈组…

Git Push 失败:HTTP 413 Request Entity Too Large

Git Push 失败&#xff1a;HTTP 413 Request Entity Too Large 问题排查 在使用 Git 推送包含较大编译产物的项目时&#xff0c;你是否遇到过 HTTP 413 Request Entity Too Large 错误&#xff1f;这通常并不是 Git 的问题&#xff0c;而是 Web 服务器&#xff08;如 Nginx&am…

第10章 网络与信息安全基础知识

网络概述 多模光纤的特点&#xff1a;成本低&#xff0c;宽芯线&#xff0c;聚光好&#xff0c;耗散大&#xff0c;低效&#xff0c;用于低速度、短距离的通信。 单模光纤的特点&#xff1a;成本高&#xff0c;窄芯线&#xff0c;需要激光源&#xff0c;耗散小&#xff0c;高效…

go 访问 sftp 服务 github.com/pkg/sftp 的使用踩坑,连接未关闭(含 sftp 服务测试环境搭建)

前言 最近在使用 sftp 服务时&#xff0c;被告知发起了海量的连接&#xff0c;直接把服务器搞崩&#xff0c;ip 被封了。 这是啥情况&#xff1f; golang 写的代码&#xff0c;我就正常的访问 sftp 服务&#xff0c;连接使用过后也都关闭了&#xff0c;咋会出现连接一直连着…

Linux多线程(二)之进程vs线程

文章目录 Linux进程VS线程进程和线程进程的多个线程共享关于进程线程的问题 重谈地址空间Linux线程周边的概念 Linux进程VS线程 进程和线程 进程是资源分配的基本单位&#xff08;进程是承担分配系统资源的基本实体&#xff09; 执行流也是资源&#xff01;线程是进程内部的执…

【HW系列】—web常规漏洞(文件上传漏洞)

文章目录 一、简介二、危害三、文件检测方式分类四、判断文件检测方式五、文件上传绕过技术六、漏洞防御措施 一、简介 文件上传漏洞是指Web应用程序在处理用户上传文件时&#xff0c;未对文件类型、内容、路径等进行严格校验和限制&#xff0c;导致攻击者可上传恶意文件&…

如何实现 C/C++ 与 Python 的通信

C/C 与 Python 的通信可以通过多种方式实现&#xff0c;如使用 C API、Ctypes、Cython、SWIG、Python.h 或基于共享库的调用等。其中&#xff0c;使用 Ctypes 方式最为简便&#xff0c;适合快速调用已有的 C 函数库。例如&#xff0c;通过将 C 代码编译为动态链接库&#xff08…

好用但不常用的Git配置

参考文章 文章目录 tag标签分支新仓库默认分支推送 代码合并冲突处理默认diff算法 tag标签 默认是以字母顺序排序&#xff0c;这会导致一些问题&#xff0c;比如0.5.101排在0.5.1000之后。为了解决这个问题&#xff0c;我们可以把默认排序改为数值排序 git config --global t…

ULVAC VWR-400M/ERH 真空蒸发器 Compact Vacuum Evaporator DEPOX (VWR-400M/ERH)

ULVAC VWR-400M/ERH 真空蒸发器 Compact Vacuum Evaporator DEPOX (VWR-400M/ERH)

PPT连同备注页(演讲者模式)一块转为PDF

首先&#xff0c;进入创建PDF/XPS&#xff1a; 然后进入选项&#xff1a; 发布选项-发布内容里选备注页&#xff1a; 导出的原始结果是这样的&#xff1a; 这个时候裁剪一下&#xff0c;范围为所有页面&#xff1a; 最终结果&#xff1a; 如果导出不选“备注页”而是只勾选“包…

项目三 - 任务8:实现词频统计功能

本项目旨在实现一个词频统计功能&#xff0c;通过读取文本文件并利用Java编程技巧处理和分析文本数据。首先&#xff0c;使用BufferedReader逐行读取文件内容&#xff0c;然后通过String.split(" ")方法将每行文本分割成单词数组。接下来&#xff0c;采用HashMap来存…

ollama list模型列表获取 接口代码

ollama list模型列表获取 接口代码 curl http://localhost:11434/v1/modelscoding package hcx.ollama;/*** ClassName DockerOllamaList* Description TODO* Author dell* Date 2025/5/26 11:31* Version 1.0**/import java.io.BufferedReader; import java.io.InputStreamR…

OPC Client第5讲(wxwidgets):初始界面的事件处理;按照配置文件初始化界面的内容

接上一讲&#xff0c;即实现下述界面的事件处理代码&#xff1b;并且按照配置文件初始化界面的内容&#xff08;三、&#xff09; 事件处理的基础知识&#xff0c;见下述链接五、 OPC Client第3讲&#xff08;wxwidgets&#xff09;&#xff1a;wxFormBuilder&#xff1b;基础…

【C++进阶篇】初识哈希

哈希表深度剖析&#xff1a;原理、冲突解决与C容器实战 一. 哈希1.1 哈希概念1.2 哈希思想1.3 常见的哈希函数1.3.1 直接定址法1.3.2 除留余数法1.3.3 乘法散列法&#xff08;了解&#xff09;1.3.4 平方取中法&#xff08;了解&#xff09; 1.4 哈希冲突1.4.1 冲突原因1.4.2 解…

Spring Boot——自动配置

目录 1.bean加载方式 1.1XML方式声明bean 1.2 xml 注解方式声明bean 1.3通过Configuration和Bean 1.4使用Import注解 1.5使用上下文对象在容器初始化完毕后注入bean 1.6使用ImportSelector接口 1.7实现ImportBeanDefinitionRegistrar接口 1.8bean加载方式&#xff08;…

使用 Vuex 实现用户注册与登录功能

引言 在构建具有用户认证功能的应用时&#xff0c;Vuex 可以用来管理用户的登录状态和相关信息。以下是如何使用 Vuex 来实现用户注册与登录功能的概述。 &#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端…

进程通信(管道,共享内存实现)

01. 进程通信简介 进程通信工具分为数据传输工具和共享内存两类。这里我们讨论进程通信工具(IPC)里面的管道、system V和共享内存。在理解阶层通信之间&#xff0c;我们先了解用户空间缓冲区和内核空间缓冲区两个概念。 1.1 用户空间缓冲区 存在于用户态的进程用户空间&#…