国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

數(shù)據(jù)流中的中位數(shù),確實(shí)輕敵了

開(kāi)發(fā) 前端
問(wèn)題也很簡(jiǎn)單,也就是一組數(shù)據(jù),找出它的中位數(shù),然后有所不同的是這組數(shù)據(jù)可能會(huì)新增一些其他數(shù)據(jù),也就是要我們自己維護(hù)這么一個(gè)數(shù)據(jù)結(jié)構(gòu)去盡量高效的完成它。

[[408159]]

本文轉(zhuǎn)載自微信公眾號(hào)「bigsai」,作者大賽 。轉(zhuǎn)載本文請(qǐng)聯(lián)系bigsai公眾號(hào)。

 前言

大家好,我是bigsai,今天忙到爆炸(暫不透露以后透露),給大家分享一個(gè)巧妙的問(wèn)題,五分鐘掌握。

今天在刷題時(shí)候,遇到一個(gè)hard問(wèn)題,也是挺有意思,在劍指offer的第41題和力扣【數(shù)據(jù)流中的中位數(shù)】。

題目描述是這樣的:

中位數(shù)是有序列表中間的數(shù)。如果列表長(zhǎng)度是偶數(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ù)。

其實(shí)問(wèn)題也很簡(jiǎn)單,也就是一組數(shù)據(jù),找出它的中位數(shù),然后有所不同的是這組數(shù)據(jù)可能會(huì)新增一些其他數(shù)據(jù),也就是要我們自己維護(hù)這么一個(gè)數(shù)據(jù)結(jié)構(gòu)去盡量高效的完成它。

我打開(kāi)這題力扣上的額描述,它好像就在誘惑我,告訴我什么!

然后我就以為真實(shí)的數(shù)據(jù)就在這個(gè)范圍,然后一頓操作猛如虎,一提交直接GG。不過(guò)這個(gè)問(wèn)題是個(gè)非常好的問(wèn)題,等到后面講,仔細(xì)先看看!

好了不多說(shuō)了,我們進(jìn)入正題,看看這個(gè)經(jīng)典問(wèn)題到底如何分析。

小白級(jí)別方法(無(wú)腦排序)

這個(gè)問(wèn)題的解決老少皆宜,小白也有小白的方法,題不在難,能過(guò)就行(只對(duì)小白有效哇)。

一組數(shù)據(jù)存儲(chǔ),我用數(shù)組、List都可以,而中位數(shù),其實(shí)就是中間一個(gè)(偶數(shù)兩個(gè)均值)數(shù),這個(gè)也好辦啊,排序啊!

一個(gè)ArrayList()海納百川(不定長(zhǎng)數(shù)組可以存儲(chǔ)數(shù)據(jù)),一行Arrays.sort()走天下。用編程語(yǔ)言中已經(jīng)存在的集合和API可以輕松實(shí)現(xiàn)!

分析一下這個(gè)算法的時(shí)間復(fù)雜度,每次插入時(shí)候需要排序 nlogn,查詢時(shí)間近O(1);次數(shù)多的話時(shí)間復(fù)雜度還是蠻高的。

具體代碼為:

  1. /** initialize your data structure here. */ 
  2. public MedianFinder() { 
  3.  
  4.  
  5. List<Integer>list=new ArrayList<>(); 
  6. public void addNum(int num) { 
  7.     list.add(num); 
  8.     list.sort(null); 
  9. public double findMedian() { 
  10.     if(list.size()%2==1) 
  11.         return list.get(list.size()/2); 
  12.     else { 
  13.         return (double) (list.get((list.size()-1)/2)+list.get(list.size()/2))/2; 
  14.     }  

一看結(jié)果,2000+ms,這也是一種極限了,這種方法僅限于小白,只為求過(guò)。

大白級(jí)別的方法(插入排序)

大白比小白稍微強(qiáng)一點(diǎn),比較它大一點(diǎn)嘛,懂得多一點(diǎn)。

大白看到:這個(gè)序列剛開(kāi)始沒(méi)有!然后一點(diǎn)一點(diǎn)在原有的基礎(chǔ)上增加長(zhǎng)度,如果每次都打亂排序那代價(jià)有點(diǎn)高!所以能不能復(fù)用上次已經(jīng)排好序的結(jié)果?

這不就插入排序嘛!

每次新來(lái)元素相當(dāng)于插入排序的最后一步使他有序,然后在插入……

這個(gè)流程每次插入的時(shí)候由兩個(gè)部分組成,查找和移動(dòng),其中查找花費(fèi)O(n),插入也是O(n)。時(shí)間復(fù)雜度依然是O(n)。

可以維護(hù)常數(shù)表示數(shù)據(jù)總個(gè)數(shù),查找中位數(shù)時(shí)候可以直接根據(jù)數(shù)量查找,時(shí)間復(fù)雜度為O(1).這樣的時(shí)間復(fù)雜度在插入上優(yōu)化為O(n)相比O(nlogn)有很大的提升。

但是聰明的大白還能發(fā)現(xiàn)一些閃光點(diǎn),數(shù)組前面有序的,只是插入最后一個(gè)元素需要鎖定在有序順序結(jié)構(gòu)中的位置,線性一個(gè)個(gè)查找太耗時(shí)了哇!這明顯就是一個(gè)二分應(yīng)用的場(chǎng)景么!可以使用二分法找到插入的位置,然后插入。

二分+插入的時(shí)間復(fù)雜度是多少呢?

記住,不是O(logn),二分查找每一次的時(shí)間復(fù)雜度確實(shí)是O(logn),但插入操作的時(shí)間復(fù)雜度依舊是O(n),總的時(shí)間復(fù)雜度取最高量級(jí) O(logn)+O(n)=O(n)。

所以這里以后如果遇到某個(gè)面試官問(wèn)你:插入排序使用二分查找優(yōu)化時(shí)間復(fù)雜度是多少?你一定要堅(jiān)定的回答:是O(n2),從單詞操作來(lái)看,雖然查詢變?yōu)镺(logn)但是插入依舊O(n),所以n個(gè)數(shù)時(shí)間復(fù)雜度依舊為O(n2)。

好了既然解釋清楚,一頓操作猛如虎,直接上代碼:

  1. class MedianFinder { 
  2.  
  3.     /** initialize your data structure here. */ 
  4.     public MedianFinder() { 
  5.  
  6.     } 
  7.     int arr[]=new int[50000]; 
  8.     int count=0; 
  9.     public void addNum(int num) { 
  10.         int low=0,high=count-1; 
  11.         while (low <= high) { 
  12.             int mid = (low + high) / 2; 
  13.             int midVal = arr[mid]; 
  14.  
  15.             if (midVal < num) 
  16.                 low = mid + 1; 
  17.             else if (midVal > num) 
  18.                 high = mid-1 ; 
  19.             else  
  20.                 low++; 
  21.         } 
  22.  
  23.         for(int i=count-1;i>=low;i--){ 
  24.             arr[i+1]=arr[i]; 
  25.         } 
  26.         arr[low]=num; 
  27.         count++; 
  28.     } 
  29.     public double findMedian() { 
  30.  
  31.         if(count%2==1) 
  32.             return arr[count/2]; 
  33.         else  
  34.             return (double) (arr[count/2-1]+arr[count/2])/2; 
  35.     } 

提交之后,200+ms,比起前面小白的無(wú)腦排序優(yōu)化了很多,但只擊敗了10%用戶,說(shuō)明方法還是不夠好,還是很白。

大佬的解法(雙堆/優(yōu)先隊(duì)列)

這個(gè)問(wèn)題的話其實(shí)也能想出來(lái),但是確實(shí)除了這個(gè)問(wèn)題沒(méi)見(jiàn)到兩個(gè)隊(duì)這么玩的,也算是打開(kāi)眼界一回。

在前面,我們講過(guò)堆排序 和優(yōu)先隊(duì)列的原理 ,里面詳細(xì)的講解了 堆這種數(shù)據(jù)結(jié)構(gòu),我們簡(jiǎn)單回顧一下堆:

堆是一種完全二叉樹(shù)(即最后一層從左向右存在節(jié)點(diǎn)連續(xù)),因?yàn)槭峭耆鏄?shù)我們經(jīng)常用數(shù)組存儲(chǔ),可以通過(guò)二叉樹(shù)下標(biāo)轉(zhuǎn)換很好的鎖定位置進(jìn)行交換。

堆分為大根堆和小根堆:

如果所有節(jié)點(diǎn)大于孩子節(jié)點(diǎn)值,那么這個(gè)堆叫做大根堆,堆的最大值在根節(jié)點(diǎn)。

如果所有節(jié)點(diǎn)小于孩子節(jié)點(diǎn)值,那么這個(gè)堆叫做小根堆,堆的最小值在根節(jié)點(diǎn)。

了解完這些基本解決這題就夠了,這里不需要知道堆、優(yōu)先隊(duì)列的具體實(shí)現(xiàn)。但是堆和優(yōu)先隊(duì)列,怎么應(yīng)用到這個(gè)中位數(shù)查找呢?

這個(gè)就很巧妙了,我們將數(shù)據(jù)等半分到兩個(gè)堆中,其中一個(gè)是小根堆,一個(gè)是大根堆,小根堆存最大的一半數(shù)據(jù),大的中最小的在堆頂;大根堆存最小的一半數(shù)據(jù),小的中最大的在堆頂,中位數(shù)就只可能在兩個(gè)堆頂部分產(chǎn)生啦!

但是在具體實(shí)現(xiàn)過(guò)程中,也有很多需要注意的地方,再添加時(shí)候要先判斷和其中一個(gè)堆頂比較大小,應(yīng)該加到哪一個(gè)堆(優(yōu)先隊(duì)列)中,但是添加之后可能數(shù)值一直遞增很大或者數(shù)值一直遞減很小可能造成兩個(gè)堆元素?cái)?shù)量不平衡,那么就要將其中少的加到多的中。

這里我在實(shí)現(xiàn)的時(shí)候約束小根堆的元素個(gè)數(shù)等于大根堆個(gè)數(shù)(偶數(shù))或者等于大根堆個(gè)數(shù)加一(奇數(shù)),在奇數(shù)情況就直接取小根堆頂返回即可。因?yàn)镴ava已經(jīng)實(shí)現(xiàn)優(yōu)先隊(duì)列,你不需要詳細(xì)實(shí)現(xiàn)其中細(xì)節(jié)(大佬可以試試參考以前我寫的優(yōu)先隊(duì)列實(shí)現(xiàn))。

分析這個(gè)時(shí)間復(fù)雜度,每個(gè)堆插入、刪除的時(shí)間復(fù)雜度級(jí)別是O(log n/2),即使如果面臨元素平衡可能多操作兩次,但是時(shí)間復(fù)雜度還是O(logn)級(jí)別。比起O(n)快了不少,數(shù)據(jù)量越大體現(xiàn)越明顯。

具體代碼為:

  1. class MedianFinder { 
  2.  
  3.     /** initialize your data structure here. */ 
  4.     public MedianFinder() { 
  5.  
  6.     } 
  7.     Queue<Integer>q1=new PriorityQueue<>();//小根堆 放大的數(shù)據(jù) 
  8.     //大根堆 
  9.     Queue<Integer>q2=new PriorityQueue<>(new Comparator<Integer>() { 
  10.         @Override 
  11.         public int compare(Integer o1, Integer o2) { 
  12.             return o2-o1; 
  13.         } 
  14.     }); 
  15.     public void addNum(int num) { 
  16.        if(q1.isEmpty()) 
  17.             q1.add(num); 
  18.         else if(num>q1.peek()){//插入到小根堆 
  19.             q1.add(num); 
  20.            if (q1.size()>q2.size()+1){ 
  21.               q2.add(q1.poll()); 
  22.             } 
  23.         } 
  24.         else{//插入到大根堆 
  25.             q2.add(num); 
  26.             if (q2.size()>q1.size()){ 
  27.             q1.add(q2.poll()); 
  28.             } 
  29.         } 
  30.  
  31.     } 
  32.     public double findMedian() { 
  33.         if(q1.size()==q2.size()) 
  34.             return (double)(q1.peek()+q2.peek())/2; 
  35.         else  
  36.             return q1.peek(); 
  37.     } 

執(zhí)行區(qū)間75ms,比起上一個(gè)大白又好很多,這個(gè)雙堆,真的太妙了!我也是第一次見(jiàn)。

提升

對(duì)于這個(gè)問(wèn)題,還有一些妖魔鬼怪用二叉搜索樹(shù)來(lái)做,理論上也是可行的,插入效率不一定很穩(wěn)定,查詢效率比較低(二叉樹(shù)的中序排序)。

但是文初提到的場(chǎng)景問(wèn)題還是要仔細(xì)思考一下,面試場(chǎng)景很可能會(huì)問(wèn)到:

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

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

對(duì)于第一個(gè)問(wèn)題,應(yīng)該用什么方法優(yōu)化呢?

如果還是采用傳統(tǒng)的雙堆,如果數(shù)據(jù)量非常大的情況下,效率肯定還是有優(yōu)化空間,當(dāng)數(shù)據(jù)比較集中分布的時(shí)候,肯定要考慮計(jì)數(shù)排序啊!

如果數(shù)據(jù)分布在0-100之間,可以直接開(kāi)一個(gè)101大小的數(shù)組,遇到一個(gè)數(shù)就將其對(duì)應(yīng)位置值加一,不光0-100 可以這樣,在某個(gè)范圍內(nèi)都可以通過(guò)移動(dòng)表示。

然后你找到中位數(shù),只需要枚舉疊加找到中間位置的數(shù)啦。

不過(guò)你可以再進(jìn)行優(yōu)化,將這個(gè)計(jì)數(shù)排序修改一下,用數(shù)組值表示小于當(dāng)前位置值的個(gè)數(shù)。這樣這個(gè)數(shù)組值是連續(xù)遞增的,查找的時(shí)候還可以使用二分優(yōu)化。

不過(guò)具體實(shí)現(xiàn)上,可能還有一些你需要考慮的,分析算法復(fù)雜度,每次插入操作,對(duì)應(yīng)小標(biāo)以及之后值都要加一,所以操作次數(shù)不超過(guò)50,而查詢操作使用二分法也不超過(guò)10次,所以在數(shù)據(jù)比較集中 數(shù)據(jù)個(gè)數(shù)很多有大量重復(fù)情況,使用計(jì)數(shù)排序是非常好的。

另外,如果99%在0-100范圍內(nèi)也很容易哇,就是在前后邊緣特意設(shè)置0和102,超過(guò)100的放到102號(hào),小于0的放到0位置,剩下每次來(lái)x放x+1位置,因?yàn)橹形粩?shù)肯定出現(xiàn)在0-100所以這個(gè)依舊可行!

 

責(zé)任編輯:武曉燕 來(lái)源: bigsai
相關(guān)推薦

2021-10-27 10:43:36

數(shù)據(jù)流中位數(shù)偶數(shù)

2011-04-14 14:43:38

SSISTransformat

2011-12-14 15:57:13

javanio

2009-07-15 09:06:11

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

2011-04-19 09:18:02

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

2020-02-06 19:12:36

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

2016-11-14 19:01:36

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

2022-03-18 08:57:17

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

2009-08-19 10:41:12

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

2017-11-16 19:26:34

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

2024-04-18 09:02:11

數(shù)據(jù)流Mixtral混合模型

2019-12-19 14:38:08

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

2012-07-30 08:31:08

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

2014-02-11 08:51:15

亞馬遜PaaSAppStream

2013-10-21 10:58:50

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

2014-12-02 10:56:47

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

2020-08-20 11:24:31

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

2023-08-31 16:47:05

反應(yīng)式編程數(shù)據(jù)流

2023-03-17 07:39:54

開(kāi)源數(shù)據(jù)流技術(shù)

2013-10-12 12:56:46

點(diǎn)贊
收藏

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

色婷婷激情综合| 色偷偷一区二区三区| 日韩精品一区二区三区四区五区 | 国产美女精品在线观看| 国产精品传媒精东影业在线| 国产精品揄拍500视频| 久久视频精品| 亚洲自拍偷拍视频| 欧美日韩国产精品一区二区亚洲| 91久久爱成人| 亚洲永久字幕| 一道精品一区二区三区| 美女国产一区二区三区| 91视视频在线观看入口直接观看www | 国产精品自拍偷拍视频| 97视频精品| 精品中文字幕人| 日韩精品视频网站| 在线亚洲美日韩| 91在线观看高清| 男人插女人欧美| 亚洲综合色自拍一区| 久香视频在线观看| 日韩无一区二区| 成人做爰视频www网站小优视频| 日韩在线视频中文字幕| 成人搞黄视频| 国产成人成网站在线播放青青| 石原莉奈一区二区三区在线观看 | 亚洲经典视频在线观看| 亚洲精品在线免费| 久久日韩精品一区二区五区| 成人亚洲在线观看| 91久久一区二区| 蜜桃视频在线网站| 久久91超碰青草是什么| 99tv成人| 日本一级淫片演员| 国产精品高潮久久久久无| 黄色的视频在线免费观看| 亚洲韩国日本中文字幕| 成人在线视频你懂的| 亚洲bt天天射| 国产经典欧美精品| 探花国产精品| 亚洲成色999久久网站| 日韩精品三级| 国产精品一区二| 大桥未久av一区二区三区中文| 疯狂做受xxxⅹ高潮视频免费| 久久精品一本| 日本成人在线免费视频| 日韩欧美黄色动漫| 秋霞国产精品| 国产日韩欧美视频| 久久97超碰国产精品超碰| 成人伊人222| 欧美成人vr18sexvr| 国产成人福利av| 久久久人人爽| 一区二区三区国产精华| 一区二区在线观看网站| 亚洲在线视频网站| 国产在线|日韩| 91在线免费看片| 成人福利视频在线| 国产三级在线免费| 欧美激情久久久| 香蕉久久a毛片| 四虎精品一区二区永久在线观看| 欧美一区二区福利在线| 中文在线免费一区三区| 美女被啪啪一区二区| 亚洲人成亚洲人成在线观看图片 | 超碰成人在线免费| 欧美精品久久| 亚洲精品videosex极品| 欧美私密网站| 91网站免费看| 91小视频xxxx网站在线| 麻豆传媒在线视频| 欧美国产极速在线| 亚洲日本一区二区三区| 日本在线免费中文字幕| 99免费精品在线| 99re热久久这里只有精品34| 欧美福利在线观看| 日韩精品电影在线| 最猛黑人系列在线播放 | www污污在线| 美女视频黄免费的亚洲男人天堂| 久久精选视频| 天堂а√在线8种子蜜桃视频| 成人97在线观看视频| 日韩二区三区四区| 中文字幕视频在线观看| 午夜伦理精品一区| 99久久综合国产精品| 国产理论在线| 免费99视频| 在线日韩国产精品| 欧美精选一区二区三区| 亚洲77777| 久久电影一区二区| 成人国产精品视频| 香蕉久久免费电影| 青青草原国产免费| 高清一区二区三区| 亚洲全部视频| 小明精品国产一区二区三区| 久久久噜噜噜久噜久久| 91伊人久久大香线蕉| 四虎影视4hu4虎成人| 伊人再见免费在线观看高清版| 精品国产一区久久| av成人天堂| 欧美另类极品| 久久riav| 日韩欧美黄色影院| 视频一区视频二区在线观看| а√天堂官网中文在线| 久久涩涩网站| 欧美大片拔萝卜| 日韩精品成人一区二区三区| 超碰个人在线| 日本一区二区三不卡| 日韩一区二区三区观看| 米奇777在线欧美播放| 色呦呦久久久| 亚洲国产精品日韩| 日韩精品福利网站| 成人h版在线观看| 国产精品白浆| 在线国产1区| 色悠悠久久综合| 国产亚洲欧美日韩俺去了| 国产精品二区不卡| 在线视频观看国产| 特级西西444www大精品视频| 中文字幕一区二区三区四区不卡 | 精品欠久久久中文字幕加勒比| 一区二区三区韩国| 欧美激情免费视频| 亚洲久本草在线中文字幕| 国内久久婷婷综合| 国产精品99在线观看| 羞羞网站在线免费观看| 国产一区二区无遮挡| 97视频在线免费观看| 国产精品极品美女粉嫩高清在线| 欧美孕妇与黑人孕交| 国产成人亚洲精品| 4k岛国日韩精品**专区| 日韩中文娱乐网| 在线成人免费网站| www.亚洲成人| 全国精品免费看| 亚洲欧美日本国产| 欧美综合久久久| 尹人成人综合网| 2001个疯子在线观看| 青青青青草视频| 精品对白一区国产伦| 亚洲一二在线观看| 成人日韩在线电影| 日本一区二区在线视频| 亚洲成人自拍| 色综合97天天综合网| 桃花色综合影院| 91涩漫在线观看| 亚洲同志男男gay1069网站| 天天综合91| 久久精品三级| 色婷婷久久久综合中文字幕| 在线亚洲观看| 96sao精品免费视频观看| 香港经典三级在线| 国产精品视频免费一区| 亚洲色图综合久久| 一区二区不卡在线播放| 久久资源在线| 玛雅亚洲电影| 精品亚洲aⅴ乱码一区二区三区| 欧美在线观看一区| 奇米四色中文综合久久| 色婷婷av一区二区| 成人午夜激情在线| 亚洲一级毛片| 91精品店在线| 欧美成熟毛茸茸| 波多野结衣家庭教师在线| 亚州av一区二区| 四虎永久在线| 国产精品调教视频| 欧美国产禁国产网站cc| 国产一区二区三区四区老人| 亚洲视频资源| 中文在线观看免费| 精东影业在线观看| 国产肥臀一区二区福利视频|