-
當前位置:首頁 > 創(chuàng)意學院 > 技術 > 專題列表 > 正文
計算復雜度和時間復雜度(計算復雜度和時間復雜度的公式)
大家好!今天讓創(chuàng)意嶺的小編來大家介紹下關于計算復雜度和時間復雜度的問題,以下是小編對此問題的歸納整理,讓我們一起來看看吧。
開始之前先推薦一個非常厲害的Ai人工智能工具,一鍵生成原創(chuàng)文章、方案、文案、工作計劃、工作報告、論文、代碼、作文、做題和對話答疑等等
只需要輸入關鍵詞,就能返回你想要的內(nèi)容,越精準,寫出的就越詳細,有微信小程序端、在線網(wǎng)頁版、PC客戶端
官網(wǎng):https://ai.de1919.com。
創(chuàng)意嶺作為行業(yè)內(nèi)優(yōu)秀的企業(yè),服務客戶遍布全球各地,如需了解SEO相關業(yè)務請撥打電話175-8598-2043,或添加微信:1454722008
本文目錄:
一、時間復雜度怎么算
問題一:請問算法的時間復雜度是怎么計算出來的? 首先假設任意一個簡單運算的時間都是1,例如a=1;a++;a=a*b;這些運算的時間都是1.
那么例如
for(int i=0;i 問題二:數(shù)據(jù)結(jié)構中的時間復雜度怎么算???看不懂啊,有沒有具體的公式 求時間復雜度,其實是在統(tǒng)計基本操作步驟的執(zhí)行次數(shù)。
“基本操作步驟”指的是加減乘除這種。比如有一個for循環(huán),執(zhí)行N次,每次做一個加法一個乘法,那么總的操作步驟數(shù)就是2N,用大O記號就是O(N).
原理就是這么簡單,計數(shù)而已。
實際做題的時候,看清楚for循環(huán)的嵌套層數(shù),就差不離。
問題三:如何計算算法的時間復雜度 求解算法的時間復雜度的具體步驟是:⑴找出算法中的基本語句;算法中執(zhí)行次數(shù)最多的那條語句就是基本語句,通常是最內(nèi)層循環(huán)的循環(huán)體。⑵計算基本語句的執(zhí)行次數(shù)的數(shù)量級;只需計算基本語句執(zhí)行次數(shù)的數(shù)量級,這就意味著只要保證基本語句執(zhí)行次數(shù)的函數(shù)中的最高次冪正確即可,可以忽略所有低次冪和最高次冪的系數(shù)。這樣能夠簡化算法分析,并且使注意力集中在最重要的一點上:增長率。⑶用大Ο記號表示算法的時間性能。將基本語句執(zhí)行次數(shù)的數(shù)量級放入大Ο記號中。如果算法中包含嵌套的循環(huán),則基本語句通常是最內(nèi)層的循環(huán)體,如果算法中包含并列的循環(huán),則將并列循環(huán)的時間復雜度相加。例如:for(i=1;i 問題四:如何計算時間復雜度 如何計算時間復雜度
定義:如果一個問題的規(guī)模是n,解這一問題的某一算法所需要的時間為T(n),它是n的某一函數(shù) T(n)稱為這一算法的“時間復雜性”。
當輸入量n逐漸加大時,時間復雜性的極限情形稱為算法的“漸近時間復雜性”。
我們常用大O表示法表示時間復雜性,注意它是某一個算法的時間復雜性。大O表示只是說有上界,由定義如果f(n)=O(n),那顯然成立f(n)=O(n^2),它給你一個上界,但并不是上確界,但人們在表示的時候一般都習慣表示前者。
此外,一個問題本身也有它的復雜性,如果某個算法的復雜性到達了這個問題復雜性的下界,那就稱這樣的算法是最佳算法。
“大 O記法”:在這種描述中使用的基本參數(shù)是 n,即問題實例的規(guī)模,把復雜性或運行時間表達為n的函數(shù)。這里的“O”表示量級 (order),比如說“二分檢索是 O(logn)的”,也就是說它需要“通過logn量級的步驟去檢索一個規(guī)模為n的數(shù)組”記法 O ( f(n) )表示當 n增大時,運行時間至多將以正比于 f(n)的速度增長。
這種漸進估計對算法的理論分析和大致比較是非常有價值的,但在實踐中細節(jié)也可能造成差異。例如,一個低附加代價的O(n2)算法在n較小的情況下可能比一個高附加代價的 O(nlogn)算法運行得更快。當然,隨著n足夠大以后,具有較慢上升函數(shù)的算法必然工作得更快。
O(1)
Temp=i;i=j;j=temp;
以 上三條單個語句的頻度均為1,該程序段的執(zhí)行時間是一個與問題規(guī)模n無關的常數(shù)。算法的時間復雜度為常數(shù)階,記作T(n)=O(1)。如果算法的執(zhí)行時 間不隨著問題規(guī)模n的增加而增長,即使算法中有上千條語句,其執(zhí)行時間也不過是一個較大的常數(shù)。此類算法的時間復雜度是O(1)。
O(n^2)
2.1. 交換i和j的內(nèi)容
sum=0; (一次)
for(i=1;i>
問題五:時間復雜度如何計算 10分 給我十分,我告訴你答案
問題六:C語言算法的時間復雜度如何計算啊? 看看這個 每個循環(huán)都和上一層循環(huán)的參數(shù)有關。 所以要用地推公式: 設i(n)表示第一層循環(huán)的i為n時的循環(huán)次數(shù),注意到他的下一層循環(huán)次數(shù)剛好就是n,分別是0,1,2...n-1 所以,把每一層循環(huán)設一個函數(shù)分別為:j(n),k(n),t(n) 則有 i(n)=j(0)+...+j(n-1) j(n)=k(0)+...+k(n-1) k(n)=t(0)+...+t(n-1) i(0)=j(0)=k(0)=0 t(n)=1 而總循環(huán)數(shù)是i(0)+i(1)...+i(n-1) 可以根據(jù)遞推條件得出準確值 所以算法復雜度是O(i(0)+i(1)...+i(n-1))
記得采納啊
問題七:程序中的時間復雜度是怎么計算的? 算法復雜度的介紹,見百科:
baike.baidu/view/7527
時間復雜度
時間頻度
一個算法執(zhí)行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。并且一個算法花費的時間與算法中語句的執(zhí)行次數(shù)成正比例,哪個算法中語句執(zhí)行次數(shù)多,它花費時間就多。一個算法中的語句執(zhí)行次數(shù)稱為語句頻度或時間頻度。記為T(n)。
計算方法
1. 一般情況下,算法的基本操作重復執(zhí)行的次數(shù)是模塊n的某一個函數(shù)f(n),因此,算法的時間復雜度記做:T(n)=O(f(n))
分析:隨著模塊n的增大,算法執(zhí)行的時間的增長率和f(n)的增長率成正比,所以f(n)越小,算法的時間復雜度越低,算法的效率越高。
2. 在計算時間復雜度的時候,先找出算法的基本操作,然后根據(jù)相應的各語句確定它的執(zhí)行次數(shù),再找出T(n)的同數(shù)量級(它的同數(shù)量級有以下:1,Log2n ,n ,nLog2n ,n的平方,n的三次方,2的n次方,n?。?,找出后,f(n)=該數(shù)量級,若T(n)/f(n)求極限可得到一常數(shù)c,則時間復雜度T(n)=O(f(n))
例:算法:
for(i=1;i>
問題八:人臉識別的計算時間復雜度怎么算 遞歸算法的時間復雜度分析 收藏 在算法分析中,當一個算法中包含遞歸調(diào)用時,其時間復雜度的分析會轉(zhuǎn)化為一個遞歸方程求解。實際上,這個問題是數(shù)學上求解漸近階的問題,而遞歸方程的形式多種多樣,其求解方法也是不一而足,比較常用的有以下四種方法: (1)代入法(Substitution Method) 代入法的基本步驟是先推測遞歸方程的顯式解,然后用數(shù)學歸納法來驗證該解是否合理。 (2)迭代法(Iteration Method) 迭代法的基本步驟是迭代地展開遞歸方程的右端,使之成為一個非遞歸的和式,然后通過對和式的估計來達到對方程左端即方程的解的估計。 (3)套用公式法(Master Method) 這個方法針對形如“T(n) = aT(n/b) + f(n)”的遞歸方程。這種遞歸方程是分治法的時間復雜性所滿足的遞歸關系,即一個規(guī)模為n的問題被分成規(guī)模均為n/b的a個子問題,遞歸地求解這a個子問題,然后通過對這a個子間題的解的綜合,得到原問題的解。 (4)差分方程法(Difference Formula Method) 可以將某些遞歸方程看成差分方程,通過解差分方程的方法來解遞歸方程,然后對解作出漸近階估計。 下面就以上方法給出一些例子說明。 一、代入法 大整數(shù)乘法計算時間的遞歸方程為:T(n) = 4T(n/2) + O(n),其中T(1) = O(1),我們猜測一個解T(n) = O(n2 ),根據(jù)符號O的定義,對n>n0,有T(n) >
問題九:如何計算算法的時間復雜度和空間復雜度 是說明一個程序根據(jù)其數(shù)據(jù)n的規(guī)模大小 所使用的大致時間和空間
說白了 就是表示 如果隨著n的增長 時間或空間會以什么樣的方式進行增長
例
for(int i = 0; i
二、時間復雜度怎么算
時間復雜度算法記作: T(n)=O(f(n))。
算法的時間復雜度,用來度量算法的運行時間,記作:T(n)=O(f(n))。它表示隨著輸入大小n的增大,算法執(zhí)行需要的時間的增長速度可以用f(n)來描述。因為f(n)的增長速度是大于或者等于T(n)的,即T(n)=O(f(n))。
所以我們可以用f(n)的增長速度來度量T(n)的增長速度,所以我們說這個算法的時間復雜度是O(f(n))。如果一個算法的執(zhí)行次數(shù)是T(n),那么只保留最高次項,同時忽略最高項的系數(shù)后得到函數(shù)f(n),此時算法的時間復雜度就是O(f(n))。
時間復雜度
在計算機科學中,時間復雜性,又稱時間復雜度,算法的時間復雜度是一個函數(shù),它定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度的函數(shù)。時間復雜度常用大O符號表述,不包括這個函數(shù)的低階項和首項系數(shù)。
使用這種方式時,時間復雜度可被稱為是漸近的,亦即考察輸入值大小趨近無窮時的情況。為了計算時間復雜度,我們通常會估計算法的操作單元數(shù)量,每個單元運行的時間都是相同的。因此,總運行時間和算法的操作單元數(shù)量最多相差一個常量系數(shù)。
三、一文講透算法中的時間復雜度和空間復雜度計算方式
作為一名“程序猿”,大家應該都聽過這么一句話:程序=數(shù)據(jù)結(jié)構+算法。
這句話是由瑞士計算機科學家尼古拉斯·沃斯(Niklaus Wirth)在 1984 年獲得圖靈獎時說的一句話,這位大佬還以這句話為名出了一本書《Algorithms + Data Structures=Programs》,從此這句話就成為了大家耳熟能詳?shù)囊痪涿浴?
隨著時間的推移,不管這句話是不是非常準確,但至少能說明數(shù)據(jù)結(jié)構與算法對程序來說是非常核心的基礎,如果我們想要寫出更多優(yōu)秀優(yōu)雅的代碼,那么數(shù)據(jù)結(jié)構與算法是必須要掌握好的。
很多人可能覺得,我不會算法,代碼一樣寫得很"溜",算法這東西似乎用處不大?,F(xiàn)在互聯(lián)網(wǎng)的發(fā)達,我們想要什么幾乎都可以在網(wǎng)上找到現(xiàn)成的,各種框架功能十分強大,似乎看起來確實不用算法也可以寫出“好代碼”。然而假如我們不懂算法,比如項目中用到了排序,我們?nèi)绾卧u估代碼的執(zhí)行效率?再比如最常用的 ArrayList 和 LinkedList ,我們該如何選擇,又比如說我們需要去集合中找某一個數(shù),又該如何寫出性能優(yōu)秀的代碼呢?
同樣的代碼,如何判斷誰的代碼是優(yōu)秀的代碼?可讀性,可擴展性,健壯性可能都可以用來判定,然而這些東西我覺得并不能直接體現(xiàn)出你代碼的優(yōu)秀,因為對用戶而言,訪問你的代碼響應速度快那就是優(yōu)秀的代碼,相反,動輒響應幾秒甚至更長時間的接口,恐怕就算你可讀性再好,再健壯也稱不上是好代碼。
所以說一段代碼是否優(yōu)秀,最直接的判斷標準就是性能,而如果要寫出高性能的代碼,那么就必須要了解算法,而且拋開這個因素,但凡不想一輩子都寫 CRUD 代碼的,也需要去了解算法,我們使用的很多框架和中間件底層都有數(shù)據(jù)結(jié)構和算法的身影,學好算法對我們源碼閱讀時理解其設計思想也是大有裨益的。
要說功利性的目的,那就是面試,目前很多大廠的面試,算法基本必面,所以想進大廠的話,咱們也得好好學學算法。
提到算法,很多人的第一反應就是太難學了,學不會,或者說經(jīng)常是看完就忘了,但是其實對于我們一個普通的開發(fā)者而言,因為并不需要我們?nèi)グl(fā)明算法,我們需要的僅僅只是去靈活的運用算法,所以并不需要非常扎實的數(shù)據(jù)基礎,當然基本的數(shù)學常識還是要有的。
如果說需要去發(fā)明設計一款算法,那就要去推導去證明算法的可行性,這種是需要具有非常扎實的數(shù)學基礎的,一般人確實無法做到,然而我們普通程序員口中提到算法無非是二分查找法,哈希算法等,高級一點的就還有回溯,貪心,動態(tài)規(guī)劃等等,這些所謂的算法都是已經(jīng)有現(xiàn)成的公式了,我們要做的無非就是理解它,然后靈活的運用它。這就和我們以前學習數(shù)學公式一樣,給你一個公式,然后你去做題,做題的過程其實就是去靈活地運用這個公式。
算法也是同理,都是有特定方法和特定思路的,我們也并不需要去推導證明這種方式為什么可行,所以學習算法沒有其他訣竅,就是先理解思路,然后多練,等熟練了,自然就可以靈活運用了,也不會說學了立刻就忘了。學完就忘無非兩個原因,一是沒理解,二是沒有練習鞏固。
數(shù)據(jù)結(jié)構與算法經(jīng)常是放在一起講,這兩者是沒辦法獨立的,因為算法是為了達到某種目的的一種實現(xiàn)方式,而數(shù)據(jù)結(jié)構是一種載體,也就是說算法必須依賴數(shù)據(jù)結(jié)構這種載體,否則就是空談。換句話說:數(shù)據(jù)結(jié)構是為算法服務的,而算法又需要作用在特定的數(shù)據(jù)結(jié)構之上。
一個算法到底好不好,我們?nèi)绾稳ピu價?前面我們提到了,你的代碼好不好,最直觀的就是看響應速度,算法也一樣,同樣實現(xiàn)一個目的(比如說排序),誰的算法速度快,我們就可以認為誰的算法更優(yōu),如果說兩種算法實現(xiàn)的速度差不多,那么我們還可以去評價算法所占用的空間,誰占用的空間少,那么就可以認為誰的算法更優(yōu),這就是算法的基礎:時間復雜度和空間復雜度。
學習算法之前,我們必須要學會如何分析時間復雜度和空間復雜度(也就是“快”和“省”),否則自己寫出來的算法自己都不知道算法的效率。
接觸過算法的都知道,算法的時間復雜度是用大寫的“O”來表示的,比如: O(1) , O(n) , O(logn) , O(nlogn) , O(n²) 等等。
變量指的是變量,也就是一段代碼的執(zhí)行時間是隨著變量的變化而變化的,而不變指的是常量,也就是不論我的變量如何改變,執(zhí)行時間都不會改變。
接下來我們就實際的來分析下常用時間復雜度的例子來練習一下。
0(1) 復雜度算法也稱之為常數(shù)階算法。這里的 1 是用來代指常量,也就是說這個算法的效率是固定的,無論你的數(shù)據(jù)量如何變化,效率都一樣,這種復雜度也是最優(yōu)的一種算法。
上面的示例中不論有多少行代碼,時間復雜度都是屬于常數(shù)階段。換言之:只要代碼不存在 循環(huán) , 遞歸 等循環(huán)類調(diào)用,不論代碼有多少行,其復雜度都是常數(shù)階。
O(n) 復雜度算法也稱之為線性階段。比如下面這個示例我們應該怎么分析復雜度呢?
前面常量階沒分析是因為常量階比較容易理解,接下來我們就以線性階這個為例子來分析下具體是怎么得到的。
我們假設每一行代碼的執(zhí)行時間是 T ,那么上面這段代碼的執(zhí)行復雜度是多少呢?
答案很明顯,那就是 T+n*T ,也就是 (n+1)T ,而在算法中有一個原則,那就是常量可以被忽略,所以就得到了 nT ,換成大 O 表示法就是 O(n) 。
這只是一個簡略的計算過程,大家也不用較真說每行代碼執(zhí)行時間可能不一樣之類的,也不要較真說 for 循環(huán)占用了一行,下面的大括號也占用了一行,如果要較真這個,那我建議可以去想一下 1=1 為什么等于 2 。
算法中的復雜度反應的只是一個趨勢,這里 O(n) 反應的就是一個趨勢,也就是說隨著 n 的變化,算法的執(zhí)行時間是會降低的。
知道了上面的線性階,那么平方階就很好理解了,雙層循環(huán)就是平方階,同理,三次循環(huán)就是立方階, k 次循環(huán)就是 k 次方階。
O(logn) 也稱之為對數(shù)階,對數(shù)階也很常見,像二分查找,二叉樹之類的問題中會見到比較多的對數(shù)階復雜度,但是對數(shù)階也是比較難理解的一種算法復雜度。
下面我們還是來看一個例子:
這段代碼又該如何分析復雜度呢?這段代碼最關鍵的就是要分析出 while 循環(huán)中到底循環(huán)了多少次,我們觀察這個循環(huán),發(fā)現(xiàn) i 并不是逐一遞增,而是不斷地翻倍: 1->2->4->8->16->32->64 一直到等于 n 為什么才會結(jié)束,所以我們得到了這樣的一個公式: 2^x=n 。
也就是說我們只要計算出 x 的值,就得到了循環(huán)次數(shù),而根據(jù)高中的數(shù)學知識我們可以得到 x=log2n ( 2 在下面,是底數(shù),試了幾種方法都打不出來,放棄了),所以根據(jù)上面線性階的分析方法,我們省略常量,就得到了示例中的算法復雜度為 O(log2n) 。
同樣的分析方式,下面的例子,我們可以很快地分析出復雜度就為 O(log3n) :
上面得到的 log3n 我們可以再做進一步的轉(zhuǎn)換: log3n=log32 * log2n ,而 log32 (注意這幾個地方的情況 3 是底數(shù),在下面) 是一個常量,常量可以省略,所以也就得到了: O(log3n)=O(log2n) 。同樣的道理,不論底數(shù)是多少,其實最終都可以轉(zhuǎn)化成和 O(log2n) 相等,正因為如此,為了方便,我們算法中通常就會省略底數(shù),直接寫作 O(logn) 。
上面的數(shù)學公式大家如果忘了或者看不懂也沒關系,只要記住不論對數(shù)的底數(shù)是多少,我們都算作 O(logn) ,而對于一個算法的復雜度是否是對數(shù)階,還有一個簡易的判斷方法: 當循環(huán)中下標以指定倍數(shù)形式衰減,那么這就是一個對數(shù)階 。
如果理解了上面的對數(shù)階,那么這種線性對數(shù)階就非常好理解了,只需要在對數(shù)階的算法中再嵌一層循環(huán)就是線性對數(shù)階:
分析了前面這些最常用的時間復雜度,其實我們可以得到以下規(guī)律:
除了上面常用的復雜度之外,另外還有指數(shù)階,階層階,根號階等,這些接觸的相對會較少,我們就不特意做分析了,如果大家感興趣的話,可以自己去了解下。
前面我們分析的都是只有一段代碼比較復雜的情況下得到的復雜度結(jié)果,那么假如我一個算法中,有多段代碼都比較復雜呢?這時候復雜度該如何分析?
我們先看下面這個例子:
這個例子中有三個循環(huán),首先第一個,是一個常量,那么根據(jù)前面的結(jié)論,不論這個常量是多大,都屬于常量級,所以第一個循環(huán)中的復雜度為 O(1) ,第二個和第三個循環(huán)我們前面也分析過,復雜度分別為 O(n) 和 O(n²) 。
也就是這一段代碼中有三段代碼產(chǎn)生了三種不同復雜度,而且這三個復雜度可以很明顯得到的大小關系為: O(1)<o(n)<o(n²) span=""> </o(n)<o(n²)> ,像這種在同一個算法中有明確大小關系的,我們就可以直接取最大值作為這個算法的復雜度,所以這個例子中算法的復雜度就是 O(n²) 。
接下來我們再來看一個例子:
這個例子我們同樣對三段循環(huán)分別分析可以分別得到如下復雜度: O(1) , O(m) , O(n) 。這時候我們只能知道 O(1) 最小可以忽略,但是后面兩個無法卻無法確定大小,所以這時候我們需要取兩段循環(huán)復雜度之和來作為算法的復雜度,所以可以得到這個例子的算法復雜度為: O(m+n) 。
上面分析的時間復雜度都是比較簡單的,實際算法中可能會比示例中復雜的多,而且我們示例中只要是循環(huán)都是無腦循環(huán),也就是一定從頭循環(huán)到尾,然而實際中我們有時候并不需要從頭循環(huán)到尾,可能中途就會結(jié)束循環(huán),所以我們根據(jù)實際情況,又可以將時間復雜度從以下四個方面來進一步分析:
這四種類型的時間復雜度在這里只會介紹前面三種,因為第四種比較復雜,而且使用場景也非常有限,而且對于這四種復雜度的分析,大家也作為了解就可以,不敢興趣的朋友們可以跳過這一小部分,因為在絕大部分情況我們只需要分析最壞復雜度就行,也就是假設循環(huán)全部執(zhí)行完畢場景下的時間復雜度。
我們通過一個例子來理解下最好時間復雜度:
這個方法就是在一個指定數(shù)組中找到指定元素的下標,找不到就返回 -1 ,這個方法比較簡單,應該比較好理解。
注意這個方法中的循環(huán)體,如果找到元素,那么就直接返回,這就會有一個現(xiàn)象,那就是我這個循環(huán)體到底會循環(huán)多少次是不確定的,可能是 1 次,也可能是 n (假設數(shù)組的長度) 次,所以假如我們要找的元素就在數(shù)組中的第一個位置,那么我循環(huán)一次就找到了,這個算法的復雜度就是 O(1) ,這就是最好情況時間復雜度。
理解了最好時間復雜度,那么最壞時間復雜度也很好理解了,那就是數(shù)組中不存在我要找到元素,或者說最后一個值才是我要找的元素,那么這樣我就必須循環(huán)完整個數(shù)組,那么時間復雜度就是 O(n) ,這也就是最壞時間復雜度。
最好時間復雜度和最壞時間復雜度畢竟只有特殊情況才會發(fā)生,概率還是相對較小,所以我們很容易就想到我們也需要有一個平均時間復雜度。
我們簡單的來分析一下,為了便于分析,我們假設一個元素在數(shù)組和不在數(shù)組中的概率都為 1/2 ,然后假如在數(shù)組在,那么又假設元素出現(xiàn)在每個位置的概率也是一樣的,也就是每個位置出現(xiàn)元素的概率為: 1/n 。
所以最終得到的平均時間復雜度應該等于元素在數(shù)組中和元素不在數(shù)組中兩種情況相加。
因為元素在數(shù)組中的概率為 1/2 ,然后在每個位置出現(xiàn)的概率也為 1/n 。假如元素出現(xiàn)在第一個位置,復雜度為 1*(1/2n) ;假如元素出現(xiàn)在第二個位置,復雜度為 2 * (1/2n) ,最終得到當前場景下時間復雜度為: 1*(1/2n) + 2 * (1/2n) + ... + n*(1/2n) =(n+1)/4。
前面已經(jīng)假定了元素不在數(shù)組中的概率為 1/2 ,所以當前場景下的時間復雜度為: n * (1/2) ,因為元素不在數(shù)組中,那么這個算法必然會將整個循環(huán)執(zhí)行完畢,也就循環(huán)是 n 次。
最后我們把兩種情況的復雜度之和相加就得到了平均時間復雜度: (n+1)/4 + n/2 = (3n+1)/4 ,最終我們將常數(shù)類的系數(shù)忽略掉,就得到了平均時間復雜度為 O(n) 。
均攤時間復雜度的算法需要使用攤還分析法,計算方式相對有點復雜,而且使用場景很有限,本文就不做過多介紹了。
空間復雜度全稱就是漸進空間復雜度,用來表示算法的存儲空間與數(shù)據(jù)規(guī)模之間的增長關系。和時間復雜度一樣,空間復雜度也是用大 O 進行表示。
其實學會了分析時間復雜度,那么空間復雜度的分析就簡單了,主要就看我們在一個算法當中到底有沒有使用到了額外的空間來進行存儲數(shù)據(jù),然后判斷這個額外空間的大小會不會隨著 n 的變化而變化,從而得到空間復雜度。
我們來看一個給數(shù)組賦值例子,假設這就是一個算法,我們可以來分析下這個算法的空間復雜度:
一開始定義了一個變量,這里需要空間,但是這是一個常量級的(不隨 n 的變化而變化),然后再定義了一個數(shù)組,數(shù)組的長度為 n ,這里數(shù)組也需要占用空間,而且數(shù)組的空間是隨著 n 的變化而變化的,其余代碼沒有占用額外空間,所以我們就可以認為上面示例中的空間復雜度為 O(n) 。
對于算法的空間復雜度也可以簡單的進行總結(jié)一下:
本文主要講述了為什么要學習算法,也簡單減少了數(shù)據(jù)結(jié)構與算法之間的關系,隨后主要介紹了算法中的入門知識:時間復雜度和空間復雜度。想要學好算法,必須要掌握如何分析一個算法的時間復雜度和空間復雜度,只有自己會分析這兩個個衡量算法主要性能的標準,才能更好的寫出性能優(yōu)秀的算法,同時我們也講到了最好時間復雜度,最壞時間復雜度,平均時間復雜度和均攤時間復雜度,不過這四種復雜度的計算方式大家作為了解即可,等實際確實需要使用到再來回顧也不遲。
四、究竟什么是時間復雜度,怎么求時間復雜度,看這一篇就夠了
時間復雜度就是用來方便開發(fā)者估算出程序的運行時間
我們該如何估計程序運行時間呢,我們通常會估計算法的操作單元數(shù)量,來代表程序消耗的時間, 這里我們默認CPU的每個單元運行消耗的時間都是相同的。
假設算法的問題規(guī)模為n,那么操作單元數(shù)量便用函數(shù)f(n)來表示
隨著數(shù)據(jù)規(guī)模n的增大,算法執(zhí)行時間的增長率和f(n)的增長率相同,這稱作為算法的漸近時間復雜度,簡稱時間復雜度,記為 O(f(n))
這里就要說一下這個大O,什么是大O呢,很多同學說時間復雜度的時候都知道O(n),O(n^2),但說不清什么是大O
算法導論給出的解釋: 大O用來表示上界的 ,當用它作為算法的最壞情況運行時間的上界,就是對任意數(shù)據(jù)輸入的運行時間的上界。
同樣算法導論給出了例子:拿插入排序來說,插入排序的時間復雜度我們都說是O(n^2)
但是在數(shù)據(jù)本來有序的情況下時間復雜度是O(n),也就對于所有輸入情況來說,最壞是O(n^2) 的時間復雜度,所以稱插入排序的時間復雜度為O(n^2)
同樣的同理我們在看一下快速排序,都知道快速排序是O(nlogn),但是當數(shù)據(jù)已經(jīng)有序情況下,快速排序的時間復雜度是O(n^2) 的,嚴格從大O的定義來講,快速排序的時間復雜度應該是O(n^2)
但是我們依然說快速排序是O(nlogn)的時間復雜度,這個就是業(yè)內(nèi)的一個默認規(guī)定,我們這里說的O 代表的就是一般情況,不是嚴格的上界
所以這里大家知道這么一回事就好了
面試中面試官絕對不會針對快速排序的時間復雜度問題來討論O的定義, 大家知道討論的時間復雜度就是指一般情況下的時間復雜度就好了。
大家要對算法的時間復雜度有這樣的一個概念
就是同一個算法的時間復雜度不是一成不變的,和輸入的數(shù)據(jù)形式依然有關系
我們主要關心的還是一般情況下的數(shù)據(jù)形式 。
面試中說道算法的時間復雜度是多少指的都是一般情況
但是如果面試官和我們深入探討一個算法的實現(xiàn)以及性能的時候 我們就要時刻想著 數(shù)據(jù)用例的不一樣 時間復雜度也是不同的,這一點同學們要注意
這個圖中我們可以看出 不同算法的時間復雜度 在不同數(shù)據(jù)輸入規(guī)模下的差異 。
我們在決定使用那些算法的時候 ,不是時間復雜越低的越好,要考慮數(shù)據(jù)規(guī)模,如果數(shù)據(jù)規(guī)模很小 甚至可以用O(n^2)的算法比 O(n)的更合適
就像上圖中圖中 O(5n^2) 和 O(100n) 在n為20之前 很明顯 O(5n^2)是更優(yōu)的,所花費的時間也是最少的。
那我們?yōu)槭裁丛谟嬎銜r間復雜度的時候要忽略常數(shù)項系數(shù)呢,也就說O(100n) 就是O(n)的時間復雜度,O(5n^2) 就是O(n^2)的時間復雜度
而且要默認O(n) 優(yōu)于O(n^2) 呢 ?
這里就又涉及到大O的定義
因為 大O其實就是數(shù)據(jù)量級突破一個點且數(shù)據(jù)量級非常大的情況下所表現(xiàn)出的時間復雜度 ,這個點也就是 常數(shù)項系數(shù)已經(jīng)不起決定性作用的點。
例如上圖中 20 就是那個點 ,n只要大于20 常數(shù)項系數(shù)已經(jīng)不起決定性作用了。
所以我們說的時間復雜度都是省略常數(shù)項系數(shù)的,是因為一般情況下我們都是默認數(shù)據(jù)規(guī)模足夠的大,基于這樣的事實 我們給出的算法時間復雜的的一個排行如下所示:
O(1)常數(shù)階 < O(logn)對數(shù)階 < O(n)線性階 < O(n^2)平方階 < O(n^3)(立方階) < O(2^n) (指數(shù)階)
我們平時說這個 算法的時間復雜度是logn的,一定是log 以2為底n的對數(shù)么?
其實不然,也可以是以10為底n的對數(shù),也可以是以20為底n的對數(shù),但我們統(tǒng)一說 logn,也就是忽略底數(shù)的描述。
為什么可以這么做呢?
如下圖所示
假如我們有兩個算法的時間復雜度 分別是log以2為底n的對數(shù) 和 log 以10為底n的對數(shù)
那么這里如果大家還記得我們高中數(shù)學的話, 應該不能理解 以2為底n的對數(shù) = 以2為底10的對數(shù) 乘以 以10為底n的對數(shù)
那這里以2為底10的對數(shù) 是一個常數(shù),而我在上面已經(jīng)講述了我們計算時間復雜度是忽略常數(shù)項系數(shù)的
抽象一下 log 以i為底n的對數(shù) 等于 log 以j為底n的對數(shù),所以我們忽略了i,直接說是logn,正式因為logij 是就一個常數(shù)
所以,這樣就應該不難理解了 我們?yōu)槭裁春雎缘讛?shù)了
有時候,我們?nèi)ビ嬎銜r間復雜度的時候 發(fā)現(xiàn)不是一個 簡單的O(n) 或者O(n^2), 而是一個復雜的表達式,例如:
O(2*n^2 + 10*n + 1000)
那這里我們通常如何描述這個算法的時間復雜度呢,一種方法就是簡化法
去掉運行時間中的加法常數(shù)項 (因為常數(shù)項并不會因為n的增大而增加計算機的操作次數(shù))
O(2*n^2 + 10*n)
去掉常數(shù)系數(shù) (我們剛剛已經(jīng)詳細講過為什么可以去掉常數(shù)項的原因了)
O(n^2 + n)
只保留保留最高項 去掉數(shù)量級小一級的n (因為n^2 的數(shù)據(jù)規(guī)模遠大于 n),最終簡化為:
O(n^2)
如果這一步同學們理解有困難,那也可以做提取n的操作,變成 O(n(n+1)) ,省略加法常數(shù)項后 也別變成了
O(n^2)
所以最后我們說:我們這個算法的算法時間復雜度是 O(n^2)
也可以用另一種簡化的思路,當n大于40的時候 , 這個復雜度 會一直小于 O(3*n^2)
O(2*n^2 + 10*n + 1000) < O(3*n^2)
所以說 最后我們省略掉常數(shù)項系數(shù)最終時間復雜度也是 O(n^2)
我們通過一道題目,來看一下具體時間復雜度應該怎么算
題目描述:找出n個字符串中相同的兩個字符串(假設這里只有兩個相同的字符串)
一些同學可能以為解決這道題目可以采用枚舉遍歷的解法,時間復雜度是 O(n^2)
這個時間復雜度其實是不對的。
這里 一些同學忽略了字符串比較的時間消耗,這里并不像int 型數(shù)字做比較那么簡單
除了n^2 次的遍歷次數(shù)外, 字符串比較依然要消耗m次操作(m也就是字母串的長度),所以時間復雜度是 O(m*n*n)
那么我們再想一下其他解題思路
我們先排對n個字符串按字典序來排序,排序后n個字符串就是有序的,意味著兩個相同的字符串就是挨在一起
然后在遍歷一遍n個字符串,這樣就找到兩個相同的字符串了
那我們來看看這種算法的時間復雜度
快速排序時間復雜度 為O(nlogn),依然要考慮字符串的長度是m,那么快速排序每次的比較都要有m次的字符比較的操作,就是 O(m*n*logn)
之后我們還要遍歷一遍這n個字符串找出兩個相同的字符串,別忘了遍歷的時候依然要比較字符串,所以總共的時間復雜度是 O(m*n*logn + n*m)
我們對 O(m*n*logn + n*m) 進行簡化操作,把 m*n 提取出來變成 O(m*n*(logn + 1)) ,
在省略常數(shù)項最后的時間復雜度是 O(m*n*logn) , 那我們比較一下時間效率 O(m*n*logn) 是不是比第一種方法 O(m*n*n) 更快一些呢
很明顯 O(m*n*logn) 要優(yōu)于 O(m*n*n)
所以 先把字符串集合排序在遍歷一遍找到兩個相同字符串的方式要比直接暴力枚舉的方式更快 。
通過這個例子 希望大家對時間復雜的是怎么算的有一個初步的理解和認識。
以上就是關于計算復雜度和時間復雜度相關問題的回答。希望能幫到你,如有更多相關問題,您也可以聯(lián)系我們的客服進行咨詢,客服也會為您講解更多精彩的知識和內(nèi)容。
推薦閱讀: