應用演算法串講1 計算複雜度優化與組合優化

2021-10-19 10:44:05 字數 3059 閱讀 2425

從事演算法工作以來,涉獵過不少演算法。有些演算法被淘汰,有些如日中天,有些則退守在某些特定的領域中頑強地生存,並不斷給演算法工作者提供思想啟發。自己的乙個方向是演算法在產業界的應用,乙個很強烈的感受是即便新的演算法層出不窮,真正在實踐上有生命力的並不在於其思想有多炫,而是其演算法特質能夠最好地適應具體場景的需求。

這麼多演算法,什麼時候用什麼演算法,是需要梳理清晰的。然而演算法思想過於複雜,想用一兩篇文章講得面面俱到幾乎不可能。所以筆者希望用乙個系列專題試圖從應用的視角統一串講一下不同演算法,盡量少講公式,著重從思想角度關注不同演算法之間的橫向聯絡和適用條件,希望對大家應用演算法落地有些幫助。

如果說非要找一條主線串起來各種不同演算法,筆者想來想去還是要靠最優化思想。最優化是一種非常直觀的思想,一般來說是指:在有限的約束條件的下控制一些自變數使得目標(因變數)達到最大值(或最小值)的過程。所以它有以下3個核心概念

目標(因變數): f(x)

自變數(控制條件):x

約束:g(x) = 0

目標優化函式很大程度決定了演算法種類。一般「決策」相關的問題的優化目標是價值函式,「**」相關的問題優化目標是**誤差。

目標(因變數)是關於自變數的函式,而這裡的自變數可以是整數、實數、函式或程式。整數、實數及其構成的陣列、向量、矩陣作為自變數比較好理解。

函式作為自變數則構成了乙個套娃:目標函式f(f)是自變數函式f(x)的函式,這個自變數函式f(x)本身也有自己的自變數x。這種情況還比較常見,絕大部分機器學習演算法都是為了尋找乙個**函式f(x),該函式的**誤差l(f)要盡量小。

程式本身可以視作一種特殊的函式,接下來要介紹的計算複雜度優化演算法就乙個典型例子。

另外,約束條件是對自變數的約束,可以是關於自變數的一組(不)等式方程。約束不是最優化問題的必須要有的,但十分常見,而且加了約束的問題可能會更難

計算複雜度優化演算法是一類非常重要的演算法,用之前約定的最優化形式描述如下:

最小化目標:時間複雜度t(f)與空間複雜度s(f)

自變數:一段程式f

滿足條件(約束):程式f能夠實現某個特定的功能(可套娃)

對時間複雜度和空間複雜度的追求是貫穿在整個應用開發過程的。即便是機器學習相關演算法,無論是訓練還是**,都需要持續關注時間空間相關的優化以及它們之間的權衡。

這裡首先要注意的是約束本身也可以是乙個最優化問題,又構成了乙個套娃,套娃玩出了花。

具體的最優化問題可以是:

將長度為n的整數陣列劃分為m個片段(約束),最小化每個片段和的最大值(目標)——leetcode1011。

在長度為n的整數陣列中,找出乙個的和大於等於s的連續子陣列(約束),最小化子陣列的長度(目標)——leetcode209。

在長度為n的整數陣列中,找出乙個遞增子串行(約束),最大化子串行的長度(目標)——leetcode300。

裡層套娃的最優化問題往往是乙個帶約束的組合優化問題,以leetcode1011為例其形式化表述如下:

最小化目標(程式出參):所有劃分片段的子陣列和的最大值。

自變數(程式入參):長度為n的整數陣列,整數m。

約束(程式必需滿足邏輯):將整數陣列劃分為m個子片段。

這類組合優化問題難以通過梯度下降法之類的方法自動化處理,往往需要在可行約束空間中遍歷可行解才能找到最優值。所以關鍵的是利用題目的特點降低遍歷的時間複雜度。處理它們的方法包括二分查詢、快慢指標、貪心與動態規劃等,分別適合處理最優化問題存在全域性單調(有序)性、可行約束空間可排除、子問題之間的約束存在遞推關係等情況,本質都是降低遍歷可行約束空間的計算量

組合優化不僅僅是存在於面試題中,在產業實踐中也屢屢能看到他們的身影。而且目前的乙個趨勢是比較多地與機器學習、強化學習等方法結合。

當然,產業應用中的組合優化可能沒有前面例子中存在多種特定簡化條件那麼理想。真實的情況可能極其複雜,如外賣訂單聚和與分配等等。實踐中的處理方式可能會放棄全域性最優的探索,而是爭取一些好的區域性最優結果,降低可行約束的探索空間。如在序列化標註過程中可以用全域性最優的維特比演算法,但在機器翻譯的推斷過程中的可行空間十分巨大,便採用beam search這樣近似區域性最優的演算法以降低探索空間。

回過頭來看外層套娃的最優化問題,其目的就是找出乙個最佳的可執行的程式。而這個是需要人手動寫出來的。那有沒有能夠自動化程式設計的演算法呢?

這其實是人工智慧的終極夢想,只是目前還做不到。但對於特的任務還是可以的,而且需要外界給機器喂資料教它——而這恰恰是接下來要介紹的機器學習演算法的核心思路。我們將在接下來的文章中重點**。

以下是整個系列文章打算**的內容,當然隨著系列的撰寫可能會調整。

1 演算法複雜度

演算法是用於解決特定問題的一系列的執行步驟,使用不同演算法,解決痛乙個問題,效率可能相差非常大.package zh.algorithm public class fibonacci 方法2 迴圈,複雜度為o n public static int fib2 int n return second ...

計算時間複雜度與空間複雜度

如何衡量乙個演算法的好壞?複雜度 空間複雜度 時間複雜度 事後統計法 就是在演算法的程式執行結束後,根據實際執行結果衡量演算法好壞 事前估計法 就是在程式執行之前,先按照程式 來預估演算法的好壞 時間複雜度 用基本指令的執行次數而不是執行時間代表時間複雜度,同乙個程式在不同配置的機器下的執行時間不一...

演算法的複雜度 時間複雜度與空間複雜度

通常,對於乙個給定的演算法,我們要做 兩項分析。第一是從數學上證明演算法的正確性,這一步主要用到形式化證明的方法及相關推理模式,如迴圈不變式 數學歸納法等。而在證明演算法是正確的基礎上,第二步就是分析演算法的時間複雜度。演算法的時間複雜度反映了程式執行時間隨輸入規模增長而增長的量級,在很大程度上能很...