成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

每日算法:數(shù)據(jù)流的中位數(shù)

開發(fā) 前端 算法
如果插入元素比大頂堆的堆頂要大,則將該元素插入到小頂堆中;如果要小,則插入到大頂堆中。

[[431427]]

本文轉(zhuǎn)載自微信公眾號(hào)「三分鐘學(xué)前端」,作者sisterAn  。轉(zhuǎn)載本文請(qǐng)聯(lián)系三分鐘學(xué)前端公眾號(hào)。

中位數(shù)是有序列表中間的數(shù)。如果列表長度是偶數(shù),中位數(shù)則是中間兩個(gè)數(shù)的平均值。

例如,

[2,3,4] 的中位數(shù)是 3

[2,3] 的中位數(shù)是 (2 + 3) / 2 = 2.5

設(shè)計(jì)一個(gè)支持以下兩種操作的數(shù)據(jù)結(jié)構(gòu):

  • void addNum(int num)- 從數(shù)據(jù)流中添加一個(gè)整數(shù)到數(shù)據(jù)結(jié)構(gòu)中。
  • double findMedian() - 返回目前所有元素的中位數(shù)。

示例:

  1. addNum(1) 
  2. addNum(2) 
  3. findMedian() -> 1.5 
  4. addNum(3)  
  5. findMedian() -> 2 

進(jìn)階:

  • 如果數(shù)據(jù)流中所有整數(shù)都在 0 到 100 范圍內(nèi),你將如何優(yōu)化你的算法?
  • 如果數(shù)據(jù)流中 99% 的整數(shù)都在 0 到 100 范圍內(nèi),你將如何優(yōu)化你的算法?

看到這個(gè)動(dòng)態(tài)數(shù)組獲取中位數(shù)問題,不要太激動(dòng),這太適合使用堆了,考察的就是堆的經(jīng)典應(yīng)用:中位數(shù)問題,詳情可查看 前端進(jìn)階算法9:看完這篇,再也不怕堆排序、Top K、中位數(shù)問題面試了

解法:利用堆

解題思路:

這里需要維護(hù)兩個(gè)堆:

  • 大頂堆:用來存取前 n/2 個(gè)小元素,如果 n 為奇數(shù),則用來存取前 Math.floor(n/2) + 1 個(gè)元素
  • 小頂堆:用來存取后 n/2 個(gè)小元素

那么,根據(jù)題目要求,中位數(shù)就為:

  • n 為奇數(shù):中位數(shù)是大頂堆的堆頂元素
  • n 為偶數(shù):中位數(shù)是大頂堆的堆頂元素與小頂堆的堆頂元素的平均值

當(dāng)數(shù)組為動(dòng)態(tài)數(shù)組時(shí),每當(dāng)數(shù)組中插入一個(gè)元素時(shí),都需要如何調(diào)整堆喃?

如果插入元素比大頂堆的堆頂要大,則將該元素插入到小頂堆中;如果要小,則插入到大頂堆中。

當(dāng)插入完成后,如果大頂堆、小頂堆中元素的個(gè)數(shù)不滿足我們已上的要求,我們就需要不斷的將大頂堆的堆頂元素或小頂堆的堆頂元素移動(dòng)到另一個(gè)堆中,直到滿足要求

代碼實(shí)現(xiàn):

  1. let MedianFinder = function() { 
  2.     // 大頂堆,用來保存前 n/2 小的元素 
  3.     this.lowHeap = new MaxHeap() 
  4.     // 小頂堆,用來保存后 n/2 小的元素 
  5.     this.hightHeap = new MinHeap() 
  6. }; 
  7. // 插入元素 
  8. MedianFinder.prototype.addNum = function(num) { 
  9.     // 如果大頂堆為空或大頂堆堆頂元素小于num,則插入大頂堆 
  10.     // 否則插入到小頂堆中 
  11.     if(!this.lowHeap.getSize() || num < this.lowHeap.getHead()) { 
  12.         // 比大頂堆的堆頂小,插入到大頂堆中 
  13.         this.lowHeap.insert(num) 
  14.     } else { 
  15.         // 比小頂堆的堆頂大,插入到小頂堆中 
  16.         this.hightHeap.insert(num) 
  17.     } 
  18.  
  19.     // 比較大小頂堆的是否依然保持平衡 
  20.     if(this.lowHeap.getSize() - this.hightHeap.getSize() > 1) { 
  21.         // 大頂堆往小頂堆遷移 
  22.         this.hightHeap.insert(this.lowHeap.removeHead()) 
  23.     } 
  24.     if(this.hightHeap.getSize() > this.lowHeap.getSize()) { 
  25.         // 小頂堆向大頂堆遷移 
  26.         this.lowHeap.insert(this.hightHeap.removeHead()) 
  27.     } 
  28. }; 
  29. // 獲取中位數(shù) 
  30. MedianFinder.prototype.findMedian = function() { 
  31.     if(this.lowHeap.getSize() && this.lowHeap.getSize() === this.hightHeap.getSize()) { 
  32.         return (this.lowHeap.getHead() + this.hightHeap.getHead())/2 
  33.     } 
  34.     return this.lowHeap.getHead() 
  35. }; 

其中小頂堆定義:

  1. // 小頂堆 
  2. let MinHeap = function() { 
  3.     let heap = [,] 
  4.     // 堆中元素?cái)?shù)量 
  5.     this.getSize = ()=> heap.length - 1 
  6.     // 插入 
  7.     this.insert = (key) => { 
  8.         heap.push(key
  9.         // 獲取存儲(chǔ)位置 
  10.         let i = heap.length-1 
  11.         while (Math.floor(i/2) > 0 && heap[i] < heap[Math.floor(i/2)]) {   
  12.             swap(heap, i, Math.floor(i/2)); // 交換  
  13.             i = Math.floor(i/2);  
  14.         } 
  15.     } 
  16.     // 刪除堆頭并返回 
  17.     this.removeHead = () => { 
  18.         if(heap.length > 1) { 
  19.             if(heap.length === 2) return heap.pop() 
  20.             let num = heap[1] 
  21.             heap[1] = heap.pop() 
  22.             heapify(1) 
  23.             return num 
  24.         } 
  25.         return null 
  26.     } 
  27.     // 獲取堆頭 
  28.     this.getHead = () => { 
  29.         return heap.length > 1 ? heap[1]:null 
  30.     } 
  31.     // 堆化 
  32.     let heapify = (i) => { 
  33.         let k = heap.length-1 
  34.         // 自上而下式堆化 
  35.         while(true) { 
  36.             let minIndex = i 
  37.             if(2*i <= k && heap[2*i] < heap[i]) { 
  38.                 minIndex = 2*i 
  39.             } 
  40.             if(2*i+1 <= k && heap[2*i+1] < heap[minIndex]) { 
  41.                 minIndex = 2*i+1 
  42.             } 
  43.             if(minIndex !== i) { 
  44.                 swap(heap, i, minIndex) 
  45.                 i = minIndex 
  46.             } else { 
  47.                 break 
  48.             } 
  49.         } 
  50.     }  
  51.     let swap = (arr, i, j) => { 
  52.         let temp = arr[i] 
  53.         arr[i] = arr[j] 
  54.         arr[j] = temp 
  55.     } 

大頂堆定義:

  1. // 大頂堆 
  2. let MaxHeap = function() { 
  3.     let heap = [,] 
  4.     // 堆中元素?cái)?shù)量 
  5.     this.getSize = ()=>heap.length - 1 
  6.     // 插入大頂堆 
  7.     this.insert = (key) => { 
  8.         heap.push(key
  9.         // 獲取存儲(chǔ)位置 
  10.         let i = heap.length-1 
  11.         while (Math.floor(i/2) > 0 && heap[i] > heap[Math.floor(i/2)]) {   
  12.             swap(heap, i, Math.floor(i/2)); // 交換  
  13.             i = Math.floor(i/2);  
  14.         } 
  15.     } 
  16.     // 獲取堆頭 
  17.     this.getHead = () => { 
  18.         return heap.length > 1 ? heap[1]:null 
  19.     } 
  20.     // 刪除堆頭并返回 
  21.     this.removeHead = () => { 
  22.         if(heap.length > 1) { 
  23.             if(heap.length === 2) return heap.pop() 
  24.             let num = heap[1] 
  25.             heap[1] = heap.pop() 
  26.             heapify(1) 
  27.             return num 
  28.         } 
  29.         return null 
  30.     } 
  31.     // 堆化 
  32.     let heapify = (i) => { 
  33.         let k = heap.length-1 
  34.         // 自上而下式堆化 
  35.         while(true) { 
  36.             let maxIndex = i 
  37.             if(2*i <= k && heap[2*i] > heap[i]) { 
  38.                 maxIndex = 2*i 
  39.             } 
  40.             if(2*i+1 <= k && heap[2*i+1] > heap[maxIndex]) { 
  41.                 maxIndex = 2*i+1 
  42.             } 
  43.             if(maxIndex !== i) { 
  44.                 swap(heap, i, maxIndex) 
  45.                 i = maxIndex 
  46.             } else { 
  47.                 break 
  48.             } 
  49.         } 
  50.     }  
  51.     let swap = (arr, i, j) => { 
  52.         let temp = arr[i] 
  53.         arr[i] = arr[j] 
  54.         arr[j] = temp 
  55.     } 

復(fù)雜度分析:

時(shí)間復(fù)雜度:由于插入元素到堆的時(shí)間復(fù)雜度為 O(logn),為樹的高度;移動(dòng)堆頂元素都需要堆化,時(shí)間復(fù)雜度也為O(logn);所以,插入( addNum )的時(shí)間復(fù)雜度為 O(logn) ,每次插入完成后求中位數(shù)僅僅需要返回堆頂元素即可, findMedian 時(shí)間復(fù)雜度為 O(1)

空間復(fù)雜度:O(n)

如果數(shù)據(jù)流中所有整數(shù)都在 0 到 100 范圍內(nèi),我們可以嘗試使用計(jì)數(shù)排序,但計(jì)數(shù)排序的時(shí)間復(fù)雜度是O(n + m),其中 m 表示數(shù)據(jù)范圍,復(fù)雜度較高,這里不適合,計(jì)數(shù)排序比較適合靜態(tài)數(shù)組前k個(gè)最值問題 leetcode347:前 K 個(gè)高頻元素

leetcode:https://leetcode-cn.com/problems/find-median-from-data-stream/solution/javascriptshu-ju-liu-de-zhong-wei-shu-by-user7746o/

 

責(zé)任編輯:武曉燕 來源: 三分鐘學(xué)前端
相關(guān)推薦

2021-06-29 19:24:42

數(shù)據(jù)流數(shù)據(jù)排序

2017-11-16 19:26:34

海量數(shù)據(jù)算法計(jì)算機(jī)

2011-12-14 15:57:13

javanio

2016-11-14 19:01:36

數(shù)據(jù)流聊天系統(tǒng)web

2009-08-19 10:41:12

Java輸入數(shù)據(jù)流

2022-03-18 08:57:17

前端數(shù)據(jù)流選型

2011-04-14 14:43:38

SSISTransformat

2012-07-30 08:31:08

Storm數(shù)據(jù)流

2019-12-19 14:38:08

Flink SQL數(shù)據(jù)流Join

2011-04-19 09:18:02

SSIS數(shù)據(jù)轉(zhuǎn)換

2013-10-21 10:58:50

微軟大數(shù)據(jù)SQL Server

2009-07-15 09:06:11

Linux圖形系統(tǒng)X11的CS架構(gòu)

2020-02-06 19:12:36

Java函數(shù)式編程編程語言

2014-12-02 10:56:47

TCPIP交互數(shù)據(jù)流

2014-02-11 08:51:15

亞馬遜PaaSAppStream

2020-08-20 11:24:31

物聯(lián)網(wǎng)數(shù)據(jù)技術(shù)

2019-06-18 13:51:08

大數(shù)據(jù)流處理新興市場

2013-10-12 13:14:27

TwitterGoogle大數(shù)據(jù)

2021-06-08 05:50:00

數(shù)據(jù)流數(shù)字化轉(zhuǎn)型數(shù)字化

2010-04-28 15:52:15

數(shù)據(jù)流負(fù)載均衡
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 自拍偷拍第一页 | 亚洲一区视频在线 | 久久久久久影院 | 亚洲欧美在线观看 | 在线观看免费av网 | 亚洲免费在线播放 | 91免费电影 | 综合久久久久久久 | 日本一本在线 | 亚洲性爰 | 欧美精品一区久久 | 成人一区二区视频 | 草久网 | 国产日韩欧美激情 | 国产91中文 | 欧美精品一区三区 | 欧美专区在线 | 新超碰97 | 青青草综合网 | 91在线精品视频 | 久草视频2 | 国产91一区 | 久久久婷婷 | 一区视频 | 亚洲精品二三区 | 在线视频一区二区 | 日韩一区二区不卡 | 国产亚洲欧美在线 | 国产一极毛片 | 国产精品福利一区二区三区 | 国产在线1区 | 欧美精品久久 | www.久久久.com | 午夜国产 | 欧美日韩成人在线 | 亚洲不卡在线观看 | 欧美在线国产精品 | 亚洲一区在线免费观看 | 中文字幕久久精品 | 欧美精品久久 | 粉嫩av在线|