「轉(zhuǎn)」大 O 表示法

效率的重要性

在介紹大 O 表示法前,先看個簡單的例子。假設(shè)你的郵箱中有 10 封郵件左痢,其中一封郵件有你需要的電話號碼,在不使用搜索功能的前提下系洛,如何找到這封郵件呢俊性?

由于只有 10 封郵件,你可以逐一打開郵件瀏覽描扯,直到找到所需電話號碼的那封定页,總得來說問題不大,最多花個一兩分鐘绽诚。那如果郵箱里有 18 億封郵件呢典徊?面對這么龐大的規(guī)模,你絕對不會像剛才那樣挨個打開查找恩够,因為就算檢查每封郵件只需 1 秒卒落,你也需要不眠不休得花上 57 年才能找到需要的那封。

image

這個例子告訴我們玫鸟,在小規(guī)模范圍內(nèi)運(yùn)作良好的方法导绷,一旦規(guī)模擴(kuò)大就會變得不再適用。如果真的有那么多郵件屎飘,我們最先想到的就是通過全局搜索匹配來節(jié)約時間妥曲。

復(fù)雜度是什么

衡量算法的高效與否的標(biāo)準(zhǔn)有兩個:

  • 花更少的時間
  • 花更少的空間

這兩點(diǎn)分別對應(yīng)時間復(fù)雜度和空間復(fù)雜度。舉個例子:商場購物

開車購物法 — 開一輛大車去商場钦购,一趟買完所有的東西回家檐盟。

步行購物法 — 拎個口袋步行去商場,分幾趟買完所有的東西押桃。

開車購物法可以節(jié)省時間葵萎,但是要求你有一輛大車,該方法時間復(fù)雜度低,空間復(fù)雜度高羡忘;步行購物法可以省空間谎痢,但是要求你往返好幾趟,該方法時間復(fù)雜度高卷雕,空間復(fù)雜度低节猿。因此,現(xiàn)實(shí)生活中遇到類似的問題我們需要權(quán)衡漫雕。

大 O 表示法是什么

大 O 符號是用來描述算法復(fù)雜度的語言滨嘱,用它來反應(yīng)不同算法處理問題的效率。算法的效率體現(xiàn)在:當(dāng)輸入的任意增長時浸间,算法相對輸入的運(yùn)行時增長速度太雨。

簡單分析

  • 輸入任意增長 — 大 O 表示法關(guān)心的是,隨著輸入 n 增長而增長最快速的部分魁蒜,因為當(dāng) n 變得非常大時囊扳,其余的影響顯得微不足道。
  • 運(yùn)行時增長速度 — 算法的運(yùn)行時間取決于處理器的性能梅惯,因此很難確定其準(zhǔn)確的運(yùn)行時間宪拥。所以大 O 表示法討論的是運(yùn)行時的增長速度 。
  • 相對輸入 — 大 O 表示法可以衡量運(yùn)行時的增長速度铣减,如 “算法效率和輸入成線性關(guān)系”(O(N))

O(1) — 常數(shù)時間

這表示該算法的運(yùn)行時是固定的她君,即無論輸入多少數(shù)據(jù),算法都將花費(fèi)相同的時間葫哗。舉個例子缔刹,下面的方法接收一個數(shù)組,不管傳遞的數(shù)組中的元素數(shù)量是 1 還是 1000劣针,所花的時間是一致的校镐,因為該方法只是簡單得返回數(shù)組中的第一個元素。

function(array) {
 return array[0];
}

趨勢圖如下:

image

O(1)

O(n) — 線性時間

對于上面郵件的例子捺典,這相當(dāng)于手動查看所有的郵件鸟廓。隨著數(shù)組中元素數(shù)量增加,處理所需的時間也以相同的速率增加襟己。舉個例子引谜,下面的方法將傳入的數(shù)組的元素打印出來,console.log() 方法執(zhí)行的次數(shù)取決于數(shù)組的長度擎浴。

function logArray(array) {
 for (let i = 0; i < array.length; i++) {
 console.log(array[i]);
 }
}

趨勢圖如下

image

O(n)

O(N2), O(N3), O(N?)??— 平方時間, 立方時間, 四次方時間

算法復(fù)雜度為 O(N2) 的典型標(biāo)志是代碼中出現(xiàn)循環(huán)嵌套:

function(array){
 for (let i = 0; i < array.length; i++){
 for (let j = 0; j < array.length; j++){
 console.log(array[j]);
 }
 }
}

下圖給出 O(N) 和 O(N2) 的增長趨勢對比:

image

藍(lán)色: O(N) · 紅色: O(N2)

同理员咽,還有 O(N3)、 O(N?) 只要多嵌套幾層循環(huán)贮预,運(yùn)行時也會隨之急速增長贝室。

image

藍(lán)色: O(N) · 紅色: O(N2) · 綠色: O(N3) · 橘黃色: O(N?)

O(logN) — 對數(shù)時間

算法時間復(fù)雜度為 O(logN) 的例子是二分查找契讲,二分查找的思路是:將要查找的數(shù)與當(dāng)前數(shù)組中心值進(jìn)行比較,每次比較過濾掉當(dāng)前數(shù)組的一半滑频,因此非常高效捡偏。如下圖

image

</center>

O(logN) 的增長趨勢圖:

image

紫色: O(logN)

忽略常量

下面的方法對傳入的數(shù)組執(zhí)行兩次相同的操作:

function countUpThenDown(array) {
for (let i = 0; i < array.length; i++) {
 console.log(i);
 };
for (let i = array.length; i > 0; i--) {
 console.log(i);
 };
}

很容易想到該方法的算法效率為 O(2N)。如果在方法中再加一個非嵌套的循環(huán)峡迷,將執(zhí)行 3 次相同的操作霹琼,算法效率為 O(3N)。在數(shù)據(jù)規(guī)模很小的情況下凉当,這點(diǎn)差異是很重要的。但是大 O 表示法更加關(guān)注的是大規(guī)模數(shù)據(jù)下的性能表現(xiàn)售葡,因此通常忽略常量倍數(shù)看杭,從下面的圖表就可以看到。

image

藍(lán)色: O(N) · 紅色: O(2N) · 綠色: O(3N).

</center>

image

藍(lán)色: O(N) · 紅色: O(2N) · 綠色: O(3N).

圖一顯示了 O(N) 挟伙、 O(2N)楼雹、O(3N) 在小規(guī)模下的差異,圖二顯示這種差異在大規(guī)模的情況下微不足道尖阔。

只關(guān)心最高次冪

很少會看到函數(shù)的時間復(fù)雜度被表示成 O(N2 + N) 贮缅。實(shí)際上 O(N2 + N) 和 O(N2) 的差異只是隨著 N 的增加 Y 軸上移 N 個單位,如下圖

image

藍(lán)色: (N2 + N) · 紅色: O(N2).

可以看到?jīng)Q定真正走勢的是 N2介却,因此在許多情況下谴供,將表達(dá)式縮減到對算法影響最大的元素就夠了。有了這套規(guī)則齿坷,通常將算法時間復(fù)雜度為 O(2N3 + 5N2 + 4N + 7) 縮寫成 O(N3)桂肌。

考慮的是最差情況

function findTheMeaningOfLife(array){
 for (let i = 0; i < array.length; i++) {
 if (array[i] === 42) {
 return i;
 }
 }
}

例如上面的方法很有可能會提前結(jié)束,但是大 O 表示法考慮的是最差的情況永淌,因此該方法的時間復(fù)雜度還是 O(N)崎场。

空間復(fù)雜度

大 O 也可以用來表示空間復(fù)雜度 。當(dāng)討論空間復(fù)雜度時遂蛀,我們關(guān)注的是算法在運(yùn)行時額外分配的內(nèi)存空間谭跨。

function sayHiNTimes(n) {
 for (let i = 0; i < n; i++) {
 console.log('hi');
 }
}

上面的方法空間復(fù)雜度是 O(1) ,因為整個過程只用到一個固定的變量李滴。

function arrayOfHiNTimes(n) {
 const hiArray = [];
 for (let i = 0; i < n; i++) {
 hiArray[i] = 'hi';
 }
 return hiArray;
}

上面的方法空間復(fù)雜度是 O(N) 螃宙,因為 hiArray 的長度隨著 n 的增大而增大。

COVER FROM:http://rkhcy.github.io/2019/03/06/bigO/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末污呼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子包竹,更是在濱河造成了極大的恐慌籍凝,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饵蒂,死亡現(xiàn)場離奇詭異,居然都是意外死亡酱讶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門泻肯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人灶挟,你說我怎么就攤上這事琉朽。” “怎么了稚铣?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵箱叁,是天一觀的道長。 經(jīng)常有香客問我惕医,道長耕漱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任抬伺,我火速辦了婚禮螟够,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沛简。我一直安慰自己齐鲤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布椒楣。 她就那樣靜靜地躺著给郊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捧灰。 梳的紋絲不亂的頭發(fā)上淆九,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音毛俏,去河邊找鬼炭庙。 笑死,一個胖子當(dāng)著我的面吹牛煌寇,可吹牛的內(nèi)容都是我干的焕蹄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阀溶,長吁一口氣:“原來是場噩夢啊……” “哼腻脏!你這毒婦竟也來了鸦泳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤永品,失蹤者是張志新(化名)和其女友劉穎做鹰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鼎姐,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钾麸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炕桨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饭尝。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖献宫,靈堂內(nèi)的尸體忽然破棺而出芋肠,到底是詐尸還是另有隱情,我是刑警寧澤遵蚜,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布奈惑,位于F島的核電站,受9級特大地震影響肴甸,放射性物質(zhì)發(fā)生泄漏驻粟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一村怪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甚负,春花似錦、人聲如沸梭域。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至既穆,卻和暖如春赎懦,著一層夾襖步出監(jiān)牢的瞬間循衰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工伐蒋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人先鱼。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像焙畔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宏多,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容