在上一篇文章裏,有看到一個簡單算法題的2個解法,咱們運用了複雜度分析來判斷哪一個解法更合適。
這裏的複雜度,就是用於衡量程序的運行效率的重要度量因素。python
雖然有句俗話「無論是白貓仍是黑貓,抓到老鼠就是好貓」,這句話是站在結果導向的,沒錯。可是若是
有個程序要去處理海量數據,一個程序員寫的要執行2天,而另外一個程序員只要半小時,那麼第二種顯然更適合
咱們的實際需求。程序員
複雜度是一個關於輸入數據量n的函數。算法
要表示複雜度很簡單,用大寫O加上括號O()
將複雜度包起來就行了。好比這個代碼的複雜度是f(n),那就能夠寫成
O(f(n))
。數組
在計算複雜度的時候,有三點須要咱們記住:函數
O(1)
表示特殊複雜度舉個例子,將一個列表反轉,不用reverse()。測試
def demo_1(): a = [1, 2, 3, 4, 5] b = [0 for x in range(0,5)] #第一個for循環 n = len(a) for i in range(n): # 第二個for循環 b[n - i - 1] = a[i] print(b) if __name__ == "__main__": demo_1() ===============運行結果================== D:\Programs\Python\Python36\python.exe D:/練習/leecode/fuzadu.py [5, 4, 3, 2, 1] Process finished with exit code 0
能夠看到我先用了一個for循環建立了一個跟a列表等長度,元素全是0的列表。
而後再用一個for循環將a裏的元素倒序放入b,最終獲得一個跟a反序的列表。code
其中,每個for循環的時間複雜度都是O(n)
,2個加起來就是O(n)+O(n)
,也等於O(n+n)
,也等於O(2n)
。
也就是至關於 一段 O(n)
複雜度的代碼前後執行兩遍,它們的複雜度是一致的。it
有了上面的例子,這個也就好理解了。
假設,一個算法的複雜度是O(n²)+O(n)
,那麼能夠知道,當n愈來愈大,也就是輸入的數據量愈來愈大時,n^2的變化率要比n大的多,
因此,這時候咱們只取變化率更大的n^2來表示複雜度便可,也就是O(n²)+O(n)
等同於O(n²)
。for循環
仍是藉助上面的反轉問題,這裏再使用第二種解法。效率
def demo_2(): a = [1, 2, 3, 4, 5] tmp = 0 n= len(a) for i in range(n//2): # // 表示整數除法,返回不大於結果的一個最大整數 tmp = a[i] a[i] = a[n -i -1] a[n -i -1] = tmp print(a) if __name__ == "__main__": demo_2() ==============運行結果============== D:\Programs\Python\Python36\python.exe D:/練習/leecode/fuzadu.py [5, 4, 3, 2, 1] Process finished with exit code 0
跟第一個解法相比,第二個解法少了一個for循環,並且循環次數只是到了列表的一半,那麼時間複雜度就是O(n/2)
,
因爲複雜度與具體的常係數無關的性質,這段代碼的時間複雜度仍是 O(n)
。
可是在空間複雜度上,第二個解法開闢了一個新的變量tmp
,它與數組長度無關。
輸入是 5 個元素的數組,須要一個tmp
變量輸入是 50 個元素的數組,一樣只須要一個tmp
變量。
所以,空間複雜度與輸入數組長度無關,這就是 O(1)
。
這裏就直接上一些經驗性的結論,能夠直接拿過來用的:
O(1)
。O(n)
。O(n)+O(n)=O(2n)
,其實也是 O(n)
。O(n²)
。O(logn)
。趁熱打鐵,分析一下下面代碼的複雜度:
for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { for (k = 0; k < n; k++) { } for (m = 0; m < n; m++) { } } }
能夠先從最裏面看,最內層是2個順序結構的for循環,複雜度是O(n)
。
中間這層的又嵌套了一個for循環,因此這時候複雜度就變成了O(n^2)
。
最後,最外層又嵌套了一個for循環,因此最終的複雜度就是O(n^3)
。
雖然測試工程師的代碼對於複雜度要求不高甚至說很是低,可是我以爲理解複雜度,而且會作一些簡單的分析 仍是頗有必要的。