日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dfs时间复杂度_一文吃透时间复杂度和空间复杂度

發布時間:2024/1/23 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dfs时间复杂度_一文吃透时间复杂度和空间复杂度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習數據結構和算法的第一步(公眾號:IT猿圈)

時間復雜度

最常見的時間復雜度有哪幾種

  • 「O(1)」:Constant Complexity 常數復雜度
  • 「O(log n)」:Logarithmic ComPlexity 對數復雜度
  • 「O(n)」:Linear ComPlexity 線性時間復雜度
  • 「O(n^2)」:N square ComPlexity 平方
  • 「O(n^3)」:N cubic ComPlexity 立方
  • 「O(2^n)」:Exponential Growth 指數
  • 「O(n!)」:Factorial 階乘

分析時間復雜度的時候是不考慮前邊的系數的,比如說O(1)的話,并不代表它的復雜度是1,也可以是2、3、4...,只要是常數次的,都用O(1)表示

如何來看一段代碼的時間復雜度?

最常用的方式就是直接看這段代碼,它根據n的不同情況會運行多少次

O(1) $n=100000; echo 'hello';O(?) $n=100000; echo 'hello1'; echo 'hello2'; echo 'hello3';

第一段代碼,不管n是多少,都只執行一次,所以它的時間復雜度就是O(1)。第二個其實也同理,我們不關心系數是多少。雖然第二段代碼會執行3次echo輸出,但是不管n是多少,它都只執行3次,因此它的時間復雜度也是「常數復雜度」,也就是O(1)

在看下邊兩段代碼:

O(n) for($i = 1; $i <= $n; $i++) {echo 'hello'; }O(n^2) for($i = 1; $i <= $n; $i++) {for($j = 1; $j <= $n; $j++) {echo 'hello';} }

這兩段代碼都是隨著n的不同,它執行的次數也在發生變化,第一段代碼執行的次數和n是線性關系的,所以它的時間復雜度是「O(n)」。

第二段代碼是一個嵌套循環,當n為100的情況下,里邊的輸出語句就會執行10000次,因此它的時間復雜度就是「O(n^2)」。如果第二段代碼中的循環不是嵌套的,而是并列的,那么它的時間復雜度應該是O(2n),因為前邊的常數系數我們不關注,因此它的時間復雜度就是「O(n)」

O(log n) for($i = 1; $i <= $n; $i = $i*2) {echo 'hello'; }O(k^2)fib($n) {if ($n < 2) {return $n;}return fib($n-1) + fib($n-2); }

第一段代碼,當n=4時,循環執行2次,所以循環內部執行的次數和n的關系為log2(n),因此時間復雜度為對數復雜度「O(logn)」。第二段是一個Fibonacci(斐波拉契)數列,這里是用了遞歸的這種形式,這就牽扯到了遞歸程序在執行的時候,如何計算它的時間復雜度,它的答案是「k^n」,k是一個常數,是一個指數級的,所以簡單的通過遞歸的方式求Fibonacci數列是非常慢的,它是指數級的時間復雜度。具體指數級的時間復雜度是怎么得到的,后邊會詳細說明。下邊看一下各種時間復雜度的曲線

從這張圖中可以看到,當n比較小的時候,在10以內的話,不同的時間復雜度其實都差不多。但是如果當n繼續擴大,指數級的增長是非常快的。因此,當我們在寫程序的時候,如果能優化時間復雜度,比如說從2^n降到n^2的話,從這個曲線來看,當n較大的時候,得到的收益是非常高的。因此這也告訴我們,在平時開發業務代碼的時候,一定要對自己的時間和空間復雜度有所了解,而且是養成習慣,寫完代碼之后,下意識的分析出這段程序的時間和空間復雜度。

從圖中可以看到,如果你的時間復雜度寫砸了的話,其實帶給公司的機器或者說資源的損耗,隨著n的增大的話,是成百上千的增加,而如果你能簡化的話,對公司來說是節約很多成本的

對于不同的程序,在寫法當中完成同樣的目標,它可能會導致時間復雜度的不一樣。下邊看一個簡單的例題

從1加到2一直加到n,求它的和

小學學數學的時候,大家都知道了有兩種方法,方法一的話用程序暴力求解的話,就是從1循環到n累加。這個是一層循環,n為多少,就執行多少次累加,所以它的時間復雜度就是「O(n)」

$sum = 0; for ($i=1; $i <=$n; $i++) {$sum += $i; }

方法二就是使用一個數學的求和公式:

y = n*(n+1)/2

用這個公式,發現程序就只有一行了,所以它的時間復雜度就是O(1)了。所以可以看到,程序的不同方法,最后得到的結果雖然是一樣的,但是它的時間復雜度很不一樣

對于遞歸這種,如何分析時間復雜度?

遞歸的話,關鍵就是要了解它的遞歸過程,總共執行了遞歸語句多少次。如果是循環的話,很好理解,n次的循環就執行了n次。那么遞歸的話,其實它是層層嵌套,其實很多時候,我們就是把遞歸它的執行順序,畫出一個樹形結構,稱之為它的遞歸狀態的遞歸樹。以前邊的求Fibonacci(斐波拉契)數列的第n項為例

Fib:0,1,1,2,3,5,8,13,21...F(n) = F(n-1)+F(n-2)

我之前面試的時候遇到過這么一道題,寫的是最最簡單的用遞歸的方式實現

fib($n) {if($n < 2) {retuen $n;}return fib($n-1)+fib($n-2); }

前邊有說到它的時間復雜度是「O(k^n)」,那么怎么得到的,可以分析一下,假設此時n取6,要計算Fib(6),就看這段代碼如何執行

所以,如果想計算F(6)就引出兩個分支,F(5)和F(4),至少多出了兩次運算

如果要計算F(5)可同理得到,需要結算F(4)和F(3)。如果要計算F(4)可同理得到,需要結算F(3)和F(2)。這里就可以看到兩個現象:

  • 每多展開一層的話,運行的節點數就是上邊一層的兩倍,第一層只有1個節點,第二層有2個節點,第三層就有4個節點,再下一層就是8個節點。所以它每一層的話,它的節點數,也就是執行次數,是成指數增長的。由此可見,到n的時候,它就執行了2^n次
  • 第二個可以觀察到,「有重復的節點」出現在了執行的樹里邊,比如圖中的F(4)和F(3)。如果將這個樹繼續展開,會發現F(4)、F(3)、F(2)都會被計算了很多次

正是因為有這么多大量冗余的計算,導致求6個數的Fibonacci數的話,就變成了2^6次方這么一個時間復雜度。因此在面試中遇到這類題,盡量別用這種方式寫,否則怕是直接涼涼了。可以加一個緩存,把這些中間結果能夠緩存下來(用數組或哈希存起來,有重復計算的數值,再從里邊找),或者直接用一個循環來寫

主定理

介紹一個叫主定理的東西,這個定理為什么重要,就是因為這個主定理的話,其實它是用來解決所有遞歸的函數,怎么來計算它的時間復雜度。主定理本身的話,數學上來證明相對比較復雜(關于主定理可以參考維基百科:https://zh.wikipedia.org/wiki/%E4%B8%BB%E5%AE%9A%E7%90%86)

也就是說,任何一個分治或者遞歸的函數,都可以算出它的時間復雜度,怎么算就是通過這個主定理。本身比較復雜的話,那怎樣化簡為實際可用的辦法,其實關鍵就是這四種,一般記住就可以了

一般在各種遞歸的情形的話,有上邊這四種情形,是在面試和平時工作中會用上

「二分查找(Binary search)」:一般發生在一個數列本身有序的時候,要在有序的數列中找到目標數,所以它每次都一分為二,只查一邊,這樣的話,最后它的時間復雜度是「O(logn)」

「二叉樹遍歷(Binary tree traversal)」:如果是二叉樹遍歷的話,它的時間復雜度為「O(n)」。因為通過主定理可以知道,它每次要一分為二,但是每次一分為二之后,每一邊它是相同的時間復雜度。最后它的遞推公式就變成了圖中T(n)=2T(n/2)+O(1)這樣。最后根據這個主定理就可以推出它的運行時間為O(n)。當然這里也有一個簡化的思考方式,就是二叉樹的遍歷的話,會「每一個節點都訪問一次,且僅訪問一次,所以它的時間復雜度就是O(n)」

「二維矩陣(Optimal sorted matrix search)」:在一個排好序的二維矩陣中進行二分查找,這個時候也是通過主定理可以得出時間復雜度是「O(n)」,記住就可以了

「歸并排序(merge sort)」:所有排序最優的辦法就是「nlogn」,歸并排序的時間復雜度就是O(nlogn)

常見的關于時間復雜度的面試題

「二叉樹的遍歷-前序、中序、后序:時間復雜度是多少?」

答案是:「O(n)」,這里的n代表二叉樹里邊樹的節點的總數,不管是哪種方式遍歷,每個節點都有且僅訪問一次,所以它的復雜度是線性于二叉樹的節點總數,也就是O(n)

「圖的遍歷:時間復雜度是多少?」

答案:「O(n)」,圖中的每一個節點也是有且僅訪問一次,因此時間復雜度也是O(n),n為圖中的節點總數

「搜索算法:DFS(深度優先)、BFS(廣度優先)時間復雜度是多少?」

答案:「O(n)」,后邊的文章會詳細介紹這兩種算法(n為搜索空間中的節點總數)

「二分查找:時間復雜度是多少?」

答案:「O(logn)」

空間復雜度

空間復雜度和時間復雜度的情況其實類似,但是它更加的簡單。用最簡單的方式來分析即可。主要有兩個原則:

如果你的代碼中開了數組,那么數組的長度基本上就是你的空間復雜度。比如你開了一個一維的數組,那么你的空間復雜度就是O(n),如果開了一個二維的數組,數組長度是n^2,那么空間復雜度基本上就是n^2

如果是有遞歸的話,那么它遞歸最深的深度,就是你空間復雜度的最大值。如果你的程序里邊遞歸中又開了數組,那么空間復雜度就是兩者的最大值

在快速變化的技術中尋找不變,才是一個技術人的核心競爭力。知行合一,理論結合實踐

總結

以上是生活随笔為你收集整理的dfs时间复杂度_一文吃透时间复杂度和空间复杂度的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。