時(shí)間復(fù)雜度與空間復(fù)雜度的計(jì)算

算法(Algorithm)是指用來操作數(shù)據(jù)、解決程序問題的一組方法帜乞。算法是大廠、外企面試的必備項(xiàng)筐眷,也是每個(gè)高級程序員的必備技能黎烈。針對同一問題,可以有很多種算法來解決匀谣,但不同的算法在效率和占用存儲空間上的區(qū)別可能會(huì)很大照棋。

那么,通過什么指標(biāo)來衡量算法的優(yōu)劣呢振定?其中必怜,上面提到的效率可以用算法的時(shí)間復(fù)雜度來描述,而所占用的存儲空間可以用算法的空間復(fù)雜度來描述后频。

  • 時(shí)間復(fù)雜度:用于評估執(zhí)行程序所消耗的時(shí)間梳庆,可以估算出程序?qū)μ幚砥鞯氖褂贸潭取?/li>
  • 空間復(fù)雜度:用于評估執(zhí)行程序所占用的內(nèi)存空間,可以估算出程序?qū)τ?jì)算機(jī)內(nèi)存的使用程度卑惜。

在實(shí)踐中或面試中膏执,我們不僅要能夠?qū)懗鼍唧w的算法來,還要了解算法的時(shí)間復(fù)雜度和空間復(fù)雜度露久,這樣才能夠評估出算法的優(yōu)劣更米。當(dāng)時(shí)間復(fù)雜度和空間復(fù)雜度無法同時(shí)滿足時(shí),還需要從中選取一個(gè)平衡點(diǎn)毫痕。

一個(gè)算法通常存在最好征峦、平均、最壞三種情況消请,我們一般關(guān)注的是最壞情況栏笆。最壞情況是算法運(yùn)行時(shí)間的上界,對于某些算法來說臊泰,最壞情況出現(xiàn)的比較頻繁蛉加,也意味著平均情況和最壞情況一樣差。

通常,時(shí)間復(fù)雜度要比空間復(fù)雜度更容易出問題针饥,更多研究的是時(shí)間復(fù)雜度厂抽,面試中如果沒有特殊說明,講的也是時(shí)間復(fù)雜度丁眼。

時(shí)間復(fù)雜度

要獲得算法的時(shí)間復(fù)雜度筷凤,最直觀的想法是把算法程序運(yùn)行一遍,自然可以獲得户盯。但實(shí)踐中往往受限于測試環(huán)境嵌施、數(shù)據(jù)規(guī)模等因素饲化,直接測試算法要么難以實(shí)現(xiàn)莽鸭,要么誤差較大,而且理論上也沒必要對每個(gè)算法都進(jìn)行一遍測試吃靠,只需要找到一種評估指標(biāo)硫眨,獲得算法執(zhí)行所消耗時(shí)間的基本趨勢即可。

時(shí)間頻度

通常巢块,一個(gè)算法所花費(fèi)的時(shí)間與代碼語句執(zhí)行的次數(shù)成正比礁阁,算法執(zhí)行語句越多,消耗的時(shí)間也就越多族奢。我們把一個(gè)算法中的語句執(zhí)行次數(shù)稱為時(shí)間頻度姥闭,記作T(n)。

漸進(jìn)時(shí)間復(fù)雜度

在時(shí)間頻度T(n)中越走,n代表著問題的規(guī)模棚品,當(dāng)n不斷變化時(shí),T(n)也會(huì)不斷地隨之變化廊敌。那么铜跑,如果我們想知道T(n)隨著n變化時(shí)會(huì)呈現(xiàn)出什么樣的規(guī)律,那么就需要引入時(shí)間復(fù)雜度的概念骡澈。

一般情況下锅纺,算法基本操作的重復(fù)執(zhí)行次數(shù)為問題規(guī)模n的某個(gè)函數(shù),也就是用時(shí)間頻度T(n)表示肋殴。如果存在某個(gè)函數(shù)f(n)囤锉,使得當(dāng)n趨于無窮大時(shí),T(n)/f(n)的極限值是不為零的常數(shù)护锤,那么f(n)是T(n)的同數(shù)量級函數(shù)官地,記作T(n)=O(f(n)),稱O(f(n))為算法的漸進(jìn)時(shí)間復(fù)雜度蔽豺,簡稱為時(shí)間復(fù)雜度区丑。

漸進(jìn)時(shí)間復(fù)雜度用大寫O表示,所以也稱作大O表示法。算法的時(shí)間復(fù)雜度函數(shù)為:T(n)=O(f(n))沧侥;

T(n)=O(f(n))表示存在一個(gè)常數(shù)C可霎,使得在當(dāng)n趨于正無窮時(shí)總有 T(n) ≤ C * f(n)。簡單來說宴杀,就是T(n)在n趨于正無窮時(shí)最大也就跟f(n)差不多大癣朗。也就是說當(dāng)n趨于正無窮時(shí)T(n)的上界是C * f(n)。其雖然對f(n)沒有規(guī)定旺罢,但是一般都是取盡可能簡單的函數(shù)旷余。

常見的時(shí)間復(fù)雜度有:O(1)常數(shù)型O(log n)對數(shù)型扁达,O(n)線性型正卧,O(nlog n)線性對數(shù)型O(n2)平方型`跪解,`O(n3)立方型炉旷,O(nk)k次方型`,`O(2n)指數(shù)型`叉讥。

上圖為不同類型的函數(shù)的增長趨勢圖窘行,隨著問題規(guī)模n的不斷增大,上述時(shí)間復(fù)雜度不斷增大图仓,算法的執(zhí)行效率越低罐盔。

常見的算法時(shí)間復(fù)雜度由小到大依次為:Ο(1)Ο(log n)Ο(n)Ο(nlog n)Ο(n^2)Ο(n^3)<…<Ο(2^n)<Ο(n!)。

值得留意的是救崔,算法復(fù)雜度只是描述算法的增長趨勢惶看,并不能說一個(gè)算法一定比另外一個(gè)算法高效。這要添加上問題規(guī)模n的范圍帚豪,在一定問題規(guī)范范圍之前某一算法比另外一算法高效碳竟,而過了一個(gè)閾值之后,情況可能就相反了狸臣,通過上圖我們可以明顯看到這一點(diǎn)莹桅。這也就是為什么我們在實(shí)踐的過程中得出的結(jié)論可能上面算法的排序相反的原因。

如何推導(dǎo)時(shí)間復(fù)雜度

上面我們了解了時(shí)間復(fù)雜度的基本概念及表達(dá)式烛亦,那么實(shí)踐中我們怎么樣才能通過代碼獲得對應(yīng)的表達(dá)式呢诈泼?這就涉及到求解算法復(fù)雜度。

求解算法復(fù)雜度一般分以下幾個(gè)步驟:

  • 找出算法中的基本語句:算法中執(zhí)行次數(shù)最多的語句就是基本語句煤禽,通常是最內(nèi)層循環(huán)的循環(huán)體铐达。
  • 計(jì)算基本語句的執(zhí)行次數(shù)的數(shù)量級:只需計(jì)算基本語句執(zhí)行次數(shù)的數(shù)量級,即只要保證函數(shù)中的最高次冪正確即可檬果,可以忽略所有低次冪和最高次冪的系數(shù)瓮孙。這樣能夠簡化算法分析唐断,使注意力集中在最重要的一點(diǎn)上:增長率。
  • 用大Ο表示算法的時(shí)間性能:將基本語句執(zhí)行次數(shù)的數(shù)量級放入大Ο記號中杭抠。

其中用大O表示法通常有三種規(guī)則:

  • 用常數(shù)1取代運(yùn)行時(shí)間中的所有加法常數(shù)脸甘;
  • 只保留時(shí)間函數(shù)中的最高階項(xiàng);
  • 如果最高階項(xiàng)存在偏灿,則省去最高階項(xiàng)前面的系數(shù)丹诀;

下面通過具體的實(shí)例來說明以上的推斷步驟和規(guī)則。

時(shí)間復(fù)雜度實(shí)例

常數(shù)階O(1)

無論代碼執(zhí)行了多少行翁垂,只要是沒有循環(huán)等復(fù)雜結(jié)構(gòu)铆遭,那這個(gè)代碼的時(shí)間復(fù)雜度就都是O(1),如:

int i = 1;
int j = 2;
int k = 1 + 2;

上述代碼執(zhí)行時(shí)沿猜,單個(gè)語句的頻度均為1枚荣,不會(huì)隨著問題規(guī)模n的變化而變化。因此邢疙,算法時(shí)間復(fù)雜度為常數(shù)階棍弄,記作T(n)=O(1)。這里我們需要注意的是疟游,即便上述代碼有成千上萬行,只要執(zhí)行算法的時(shí)間不會(huì)隨著問題規(guī)模n的增長而增長痕支,那么執(zhí)行時(shí)間只不過是一個(gè)比較大的常數(shù)而已颁虐。此類算法的時(shí)間復(fù)雜度均為O(1)。

對數(shù)階O(log n)

先來看對應(yīng)的示例代碼:

int i = 1; // ①
while (i <= n) {
   i = i * 2; // ②
}

在上述代碼中卧须,語句①的頻度為1另绩,可以忽略不計(jì)。

語句②我們可以看到它是以2的倍數(shù)來逼近n花嘶,每次都乘以2笋籽。如果用公式表示就是1222…2 <=n,也就是說2的x次方小于等于n時(shí)會(huì)執(zhí)行循環(huán)體椭员,記作2^x <= n车海,于是得出x<=logn。也就是說上述循環(huán)在執(zhí)行l(wèi)ogn次之后隘击,便結(jié)束了侍芝,因此上述代碼的時(shí)間復(fù)雜度為O(log n)。

其實(shí)上面代碼的時(shí)間復(fù)雜度公式如果精確的來講應(yīng)該是:T(n) = 1 + O(log n)埋同,但我們上面已經(jīng)講到對應(yīng)的原則州叠,“只保留時(shí)間函數(shù)中的最高階項(xiàng)”,因此記作O(log n)凶赁。

線性階O(n)

示例代碼:

int j = 0; // ①
for (int i = 0; i < n; i++) { // ②
   j = i; // ③
   j++; // ④
}

上述代碼中咧栗,語句①的頻度為1逆甜,②的頻度為n,③的頻度為n-1致板,④的頻度為n-1忆绰,因此整個(gè)算法可以用公式T(n)=1+n+(n-1)+(n-1)來表示。進(jìn)而可以推到T(n)=1+n+(n-1)+(n-1)=3n-1可岂,即O(n)=3n-1错敢,去掉低次冪和系數(shù)即O(n)=n,因此T(n)=O(n)缕粹。

在上述代碼中for循環(huán)中的代碼會(huì)執(zhí)行n遍稚茅,因此它消耗的時(shí)間是隨著n的變化而成線性變化的,因此這類算法都可以用O(n)來表示時(shí)間復(fù)雜度平斩。

線性對數(shù)階O(nlogN)

示例代碼:

for (int m = 1; m < n; m++) {
   int i = 1; // ①
   while (i <= n) {
      i = i * 2; // ②
   }
}

線性對數(shù)階要對照對數(shù)階 O(log n)來進(jìn)行理解亚享。上述代碼中for循環(huán)內(nèi)部的代碼便是上面講到對數(shù)階,只不過在對數(shù)階的外面套了一個(gè)n次的循環(huán)绘面,當(dāng)然欺税,它的時(shí)間復(fù)雜度就是n*O(log n)了,于是記作O(nlog n)揭璃。

平方階O(n2)

示例代碼:

int k = 0;
for (int i = 0; i < n; i++) {
   for (int j = 0; j < n; j++) {
      k++;
   }
}

平方階可對照線性階來進(jìn)行理解晚凿,我們知道線性階是一層for循環(huán),記作O(n)瘦馍,此時(shí)等于又嵌套了一層for循環(huán)歼秽,那么便是n * O(n),也就是O(n * n)情组,即O(n^2)燥筷。

如果將外層循環(huán)中的n改為m,即:

int k = 0;
for (int i = 0; i < m; i++) {
   for (int j = 0; j < n; j++) {
      k++;
   }
}

那么院崇,對應(yīng)的時(shí)間復(fù)雜度便為:O(m * n)肆氓。

同理,立方階O(n3)底瓣、K次方階O(n^k)谢揪,只不過是嵌套了3層循環(huán)、k層循環(huán)而已濒持。

排序算法對比

上面介紹了各種示例算法的時(shí)間復(fù)雜度推理過程键耕,對照上面的時(shí)間復(fù)雜度以及算法效率的大小,來看一下我們常見的針對排序的幾種算法的時(shí)間復(fù)雜度對比柑营。

空間復(fù)雜度

最后屈雄,我們再了解一下空間復(fù)雜度」偬祝空間復(fù)雜度主要指執(zhí)行算法所需內(nèi)存的大小酒奶,用于對程序運(yùn)行過程中所需要的臨時(shí)存儲空間的度量蚁孔,這里的空間復(fù)雜度同樣是預(yù)估的。

程序執(zhí)行除了需要存儲空間惋嚎、指令杠氢、常數(shù)、變量和輸入數(shù)據(jù)外另伍,還包括對數(shù)據(jù)進(jìn)行操作的工作單元和存儲計(jì)算所需信息的輔助空間鼻百。存儲空間通常包括:指令空間(即代碼空間)、數(shù)據(jù)空間(常量摆尝、簡單變量)等所占的固定部分和動(dòng)態(tài)分配温艇、遞歸棧所需的可變空間。其中可變空間與算法有關(guān)堕汞。

一個(gè)算法所需的存儲空間用f(n)表示勺爱。S(n)=O(f(n))其中n為問題的規(guī)模,S(n)表示空間復(fù)雜度讯检。

下面看兩個(gè)常見的空間復(fù)雜度示例:空間復(fù)雜度O(1)和O(n)琐鲁。

空間復(fù)雜度 O(1)

空間復(fù)雜度為O(1)的情況的示例代碼與時(shí)間復(fù)雜度為O(1)的實(shí)例代碼一致:

int i = 1;
int j = 2;
int k = 1 + 2;

上述代碼中臨時(shí)空間并不會(huì)隨著n的變化而變化,因此空間復(fù)雜度為O(1)人灼∥Ф危總結(jié)一下就是:如果算法執(zhí)行所需要的臨時(shí)空間不隨著某個(gè)變量n的大小而變化,此算法空間復(fù)雜度為一個(gè)常量挡毅,可表示為 O(1)蒜撮,即 S(n) = O(1)。

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

示例代碼:

int j = 0;
int[] m = new int[n];
for (int i = 1; i <= n; ++i) {
   j = i;
   j++;
}

上述代碼中跪呈,只有創(chuàng)建int數(shù)組分配空間時(shí)與n的大小有關(guān),而for循環(huán)內(nèi)沒有再分配新的空間取逾,因此耗绿,對應(yīng)的空間復(fù)雜度為S(n) = O(n)。

總結(jié)一下

本篇文章給大家講了可以通過時(shí)間復(fù)雜度和空間復(fù)雜度來衡量算法的優(yōu)劣砾隅,同時(shí)用具體的實(shí)例來講解如何計(jì)算不同方法的時(shí)間復(fù)雜度和空間復(fù)雜度误阻。當(dāng)我們了解了這些基本的概念、函數(shù)晴埂、計(jì)算方法究反、計(jì)算規(guī)則及算法性能之后,再進(jìn)行算法的學(xué)習(xí)便可以輕松預(yù)估出算法的性能等指標(biāo)儒洛。

參考文獻(xiàn):

https://blog.csdn.net/zolalad/article/details/11848739 https://zhuanlan.zhihu.com/p/50479555

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末精耐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子琅锻,更是在濱河造成了極大的恐慌卦停,老刑警劉巖向胡,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惊完,居然都是意外死亡僵芹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門小槐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拇派,“玉大人,你說我怎么就攤上這事凿跳〖悖” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵拄显,是天一觀的道長苟径。 經(jīng)常有香客問我,道長躬审,這世上最難降的妖魔是什么棘街? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮承边,結(jié)果婚禮上遭殉,老公的妹妹穿的比我還像新娘。我一直安慰自己博助,他們只是感情好险污,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著富岳,像睡著了一般蛔糯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窖式,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天蚁飒,我揣著相機(jī)與錄音,去河邊找鬼萝喘。 笑死淮逻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阁簸。 我是一名探鬼主播爬早,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼启妹!你這毒婦竟也來了筛严?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤翅溺,失蹤者是張志新(化名)和其女友劉穎脑漫,沒想到半個(gè)月后髓抑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡优幸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年吨拍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片网杆。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羹饰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碳却,到底是詐尸還是另有隱情队秩,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布昼浦,位于F島的核電站馍资,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏关噪。R本人自食惡果不足惜鸟蟹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望使兔。 院中可真熱鬧建钥,春花似錦、人聲如沸虐沥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欲险。三九已至镐依,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間天试,已是汗流浹背馋吗。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秋秤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓脚翘,卻偏偏與公主長得像灼卢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子来农,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

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