二 複雜度優化

2021-10-07 19:25:34 字數 4139 閱讀 1573

上節說到了複雜度,簡單介紹了複雜度時間複雜度空間複雜度,同時舉了小例子來說明這幾個概念,同時也舉例說明了一下優化空間複雜度的乙個簡單概念。

複雜度的優化即**效率的優化,換句話說就是要將可行解提高到更優解,最終目標是:要採用盡可能低的時間複雜度和空間複雜度,去完成一段**的開發

如果沒有複雜度概念的情況下開發**,最直接的開發方式就是:假定在不限制時間、也不限制空間的情況下,可以完成某個任務的**的開發。這就是通常我們所說的暴力解法,更是程式優化的起點。說到優化的起點就不得不舉乙個例(慄)子來說一下:

在100以內的正整數中,獲取能夠同時滿足下列兩個條件的數字:

我能猜到大家的解法就是將這100個數字進行迴圈一遍,然後判斷同時滿足以上兩個條件的時候則返回資料。這時的時間內複雜度肯定就是o(n)了。你有沒有更好的方法呢?(當然我是沒有想到更好的辦法了啦,哈哈哈哈!!!我懶我笨我不想,但我盡量不妨礙你去想。)

**如下:

public function test()

}return $res;

}

這是一種不計較任何時間複雜度或空間複雜度的、最直觀的暴力解法。如果暴力解法複雜度夠低,可以接受,那我無話可說。繼續使用暴力解法就好,畢竟也不費腦筋,死不了多少腦細胞,保留點黑髮對程式設計師來說還是比較重要的。

言歸正傳:為了降低複雜度,我們的乙個直觀的思路是 "梳理程式,看其流程中是否有無效的計算或者無效的儲存"

好了,(敲黑板,重點來了,記一下,記一下哈!!),以上我們大概了解了基本的問題解決思路,那麼複雜度優化的思路是什麼呢?這也是本節的核心:

暴力解法:在沒有任何時間、空間約束下,完成**任務的開發(隨心所欲,為所欲為)。

無效操作剔除處理:將**中的無效計算、無效儲存剔除,降低時間或空間複雜度(把沒用的廢物通通排出體外 【這是一句有味道的話?】)。

時空轉換:

無效操作剔除處理

暴力解法 已經在上面舉例說明了,不管三七二十一,第一印象很重中,想到什麼什麼,接到需求的第乙個想法就是你的暴力解法。下面來舉例說明一下剔除無效操作的處理,請聽題:

假設有任意多張面額為 2 元、3 元、7 元的貨幣,現要用它們湊出 100 元,求總共有多少種可能性。我的想法是下面的**:

public function test4()}}

}return $count;

}

大家可以想一下這個**是否還有可優化的可能性呢?(我可能是在廢話,沒有的話我寫出來幹啥嘛,腦袋有泡了!???!)

上面的**可以很明顯的看到是三層for迴圈,那麼由之前說到的時間複雜度演算法可以得出,改**的時間複雜度為o(n) * o(n) * o(n) = o(n³)

分析:下面針對這段**進行分析,仔細看這段**,就會發現乙個問題,三種面值迴圈了三次,如果是前兩種面值的確定了,那麼第三種面值豈不是就相當於確定了呢?(你品,你再品,你細品???!!!)

所以進行改良**如下:

public function test5()}}

return $count;

}

是不是很神奇?沒錯,就是這麼神奇(我在自言自語,可能對你來說沒有那麼奇怪,也許你早就想到了,沒關係,沒想到的還大有人在),這裡我們會發現,原來有三層巢狀迴圈,現在程式設計了兩層巢狀迴圈,複雜度變成了o(n²),這裡就是經過分析後發現最內側的for迴圈是無用的,所以把最內側的for迴圈給剔除掉了,從而達到了降低複雜度的目的。

時空轉換

說完了無效操作剔除處理後我們該討論什麼是時空轉換了,所謂的時空轉換,我理解的字面意思就是時間複雜度空間複雜度轉換,那麼誰轉換誰呢?

舉個例子:

綜上所述:有些問題能解決(空間可以花錢解決),但是時間卻是花錢買不來的。(花錢能辦的事兒都不叫事兒),只能說時間是無價的,空間是有價的。

空口無憑那不行,(肯定有人在等著舉?了),廢話不多說,翠花上?:

輸入陣列 [1,2,3,4,5,5,6 ] ,在陣列中查詢出現次數最多的數值,一眼就能看到答案:5.(不錯,很不錯,答案就是5),下面上**。

public function test6()

}if ($temp_count > $temp_max)

}return $max_value;

}

上面**巢狀了兩層foreach來解決該問題,最終計算出來的值是5,巢狀兩層for迴圈可以得出時間複雜度為o(n²),當我們去檢視空間複雜度的時候會發現,我們之定義了三個變數,變數的空間複雜度是o(1),三個變數的空間複雜度就是o(1) + o(1) + o(1) = 3o(1),按照複雜度的計算規則,常數不計算在內,故複雜度是3o(1) = o(1),所以該**的空間複雜度與是o(1)時間複雜度是o(n²)

我們這是我們需要做的就是降低時間複雜度,那麼我們需要做的就是,在有限的空間內來降低時間複雜度,降低時間複雜度無疑就是將o(n²)降低到o(n)或者降低到o(1)

不賣關子了,直接上**:

public function test7()

elseif (isset($b[$item]))

}$max_value = -1;

$temp_max = 0;

foreach ($b as $key => $item)

}return $max_value;

}

這裡可以看到,我們定義的不在是三個變數,二十兩個變數和乙個陣列,並且我們把兩個巢狀的for迴圈單獨拆開了成兩個平級的for迴圈了。經過第乙個for迴圈後我們可以得到定義的乙個陣列為 k-v 結構的字典了(注意:牽扯到資料結構了)。那麼該字段的複雜度是跟隨者輸入量的變化而變化的,故空間複雜度為o(n),前面根據複雜度的計算規則來算,空間複雜度中的兩個變數為o(1)不計算在其中,所以該段**的空間複雜度為o(n)

分析時間複雜度,兩個for迴圈的時間複雜度分別是o(n),那麼合起來該段**的時間複雜度為o(n) + o(n) = 2o(n),根據計算規則,常數不算,那麼最終時間複雜度為o(n)

綜上所述:

可以發現,我們成功的將時間複雜度降低了,與此同時我們也提高了空間複雜度。但是我們做到了,利用有價的空間換回來了無價的時間,所以這一步是非常可行的。

總結一下吧

各單位注意!各部門注意:(這裡句句是精華),無論是什麼難題,其實降低複雜度的方法就是三個步驟:

暴力解法:在沒有任何時間、空間約束下,完成**任務的開發(隨心所欲,為所欲為)。

分析暴力解法後,無效操作剔除處理:將**中的無效計算、無效儲存剔除,降低時間或空間複雜度(把沒用的廢物通通排出體外 【真的有味道了?】)。

無效操作剔除處理後再分析,時空轉換:設計合理資料結構,完成時間複雜度向空間複雜度的轉移(把無價變成有價)。

上面我著重的講了分析分析再分析,我所注重的還是要去理解,要去分析,要去拆解,會到最初的初衷上,就是這段**要完成的是什麼功能,或者說是什麼業務,從源頭出發,分析拆解業務,然後轉換思路。

咚咚咚!!! 小彩蛋來嘍:上面的優化方式我們可以看到,時空轉換的時候,我們用到了k-v 結構的字典,這裡就是用到的資料結構。也就是說,我們如果涉及到操作空間複雜度的時候,我們就會涉及到資料結構,(有些小夥伴可能會說,資料結構我不會呀,沒關係,我也不會,哈哈哈哈!!!???),接下來我也會一步一步的去學習資料結構的知識,好東西就是要分享的。 ———— 那些年,我們掛過的科,遲早要還的!

時間複雜度和空間複雜度(二)

演算法的時間複雜度的定義 在進行演算法分析時,語句總的執行次數t n 是關於問題規模 n的函式,進而分析 t n 隨n 的變化情況並確定t n 的數量級。演算法的時間複雜度就是演算法時間量度,記作 t n o f n 它表示隨問題規模 n的增大,演算法執行時間的增長率和 f n 的增長率相同,稱作演...

時間複雜度和空間複雜度 二

演算法時間複雜度的定義 進行演算法分析時,語句總的執行次數t n 是關於問題規模n的函式,進而分析t n 隨n的變化情況並確定t n 的數量級。演算法的時間複雜度,也就是演算法的時間量度,記作t n o f n 它表示隨問題規模n的增大,演算法執行時間的增長率和f n 的增長率相同,稱作演算法的漸進...

複雜度分析 時間複雜度 空間複雜度

執行效率是演算法的乙個重要的考量指標,演算法的執行效率用時間 空間複雜度來衡量。今天我們來學習一下複雜度的分析。通常我們可以通過執行程式來獲得演算法的真正的執行時間,這種方法我們可以稱為事後統計法,但這種方法得到的是具體的資料,測試結果很依賴測試環境,而且受資料規模影像最大。因此,我們需要乙個不需要...