演算法基礎 - 列舉/遞迴/動歸/深廣搜/二分/貪心

Reeker丶發表於2019-03-02

筆記內容來源課程 https://www.coursera.org/learn/suanfa-jichu

列舉

概念

  • 基於已有知識進行答案猜測的求解策略
    • 對解集合中的每一項根據條件進行檢驗
    • 不重複檢驗
  • 很多情況下列舉意味著使用迴圈
  • 一般性 + 完備性

分析

原子 - 區域性 - 整體

  • 拆分出原子操作,分析每個原子操作的影響、規律
  • 確定列舉物件、範圍和判定條件
  • 逐一列舉可能的解並驗證是否是問題的解
  • 關鍵問題
    • 給出解空間,建立簡潔的數學模型,減少列舉的狀態數目
    • 減少搜尋空間,縮小各變數取值範圍,避免不必要的計算
    • 合適的搜尋順序,簡化過程,及早排除明確的錯誤答案

技巧

  • 如果存在某個區域性,一旦區域性的狀態被確定,剩餘部分的狀態只能是確定的一種或較少種,那麼只需列舉區域性狀態。固定部分,確定規律
  • 儘可選使用stl演算法和合適的資料結構來縮減時間
  • 好的排序和處理順序非常重要

遞迴

概念

  • 函式直接或間接的呼叫自身
  • 與列舉的比較
    • 列舉的子問題之間是平行的、沒有相互依存關係的,遞迴的子問題是縱向依存的

分析

  • 能劃分成相同性質的子問題,通常體現為自相似性
  • 關鍵
    • 遞迴式:如何劃分成子問題
    • 遞迴出口:如何確定最小子問題
    • 界函式:如何保證規模縮減

技巧

  • 遞迴函式使用狀態變數引數記錄狀態變化過程,當拆分出的子問題不具備自相似性時,可以通過增加狀態引數來增加限制
  • 使用狀態表維護狀態
  • 遞迴容易發生大量重複計算,使用記錄表避免重複計算
  • 用棧代替遞迴以提高效率
  • 遞迴轉化成遞推(自頂向下轉換成自底向上)
  • 遞迴轉化為動態規劃

動態規劃

性質

  • 最優子結構,問題最優解包含的子問題的解也是最優的。(最優不一定是明顯的,可能只能在相鄰一層的子問題中體現)
  • 無後效性。當某些狀態值確定後,此後所需求出的狀態值就只和這些狀態有關,而與此前通過何種路徑經過何種狀態無關
  • 人人為我/我為人人遞推型動態規劃

分析

  • 將原問題分解為子問題
    • 子問題與原問題形式相同或類似,但規模更小
    • 子問題求出的解要記錄,保證每個子問題只求解一次
  • 確定狀態
    • 和子問題相關的各個變數的一組取值是一個狀態
  • 確定初始/邊界狀態的值
    • 即填充狀態陣列的部分內容
  • 確定狀態轉移方程
    • 如何從已知的狀態求出另一狀態,即利用狀態陣列已有內容計算需要填充的其他內容
    • 類似於遞迴

技巧

  • 每次只拆除單獨一個操作單位,來尋找狀態轉移方程
  • 若無明顯確定的初始狀態,可全部初始化為某個一般值,並按照某種排序順序進行遞遍歷更新
  • 若無法形成遞推關係,則考慮細化引數列表,增加限制條件

深度&廣度優先搜尋

比較

  • 廣搜一定能獲得最優解,但具有盲目性,在搜尋過程中需要大量儲存空間,適合用queue
  • 深搜需要優化搜尋範圍,但搜尋過程需要的空間較小,適合用stack

技巧

  • 使用廣搜時,在將節點加入佇列前,可以通過對全域性陣列狀態表(Open/Closed)進行更新或是在結構型別中設定其父指標的方式,在搜尋結束後還原解的路徑
  • 雙向廣度優先搜尋能明顯減少搜尋樹的寬度

二分查詢

  • 前提:已排序的序列

技巧

  • 最小值問題 》判定性問題(二分判定在某個值時能否滿足條件)

貪心演算法

  • 求解時,做出僅當前最好的選擇
  • 不能保證全域性最優
  • 關鍵是貪心策略的選擇
  • 自頂向下分解為子問題
  • 具有無後效性

分析

  • 建立數學模型
  • 分解成子問題
  • 對每一子問題求得區域性最優解
  • 合併子問題

其他技巧

設定冗餘陣列

  • 通過填充冗餘陣列,減少邊界判斷程式碼
  • 是以空間換時間的方式,通常是利大於弊的

使用一個自增變數進行序列列舉

  • 通過迴圈自增變數,獲取各個位的01情況來獲得一個全部情況列舉
  • 或者維護一個陣列,在每次自增時判斷是否需要進位

壓縮多個01狀態至單個變數

  • 使用一個變數的各個位分別表示每個狀態,使用時用&按位與運算分別與1/2/4/8…計算後與0比較進行判斷

剪枝

  • 型別
    • 最優化剪枝(先考慮,大多與演算法整體處理思路/順序有關)
    • 可行性剪枝(後考慮,大多與處理過程中的區域性判斷有關)
  • 優先進行列舉數量少的步驟進行嘗試和排除
  • 避免計算機會出現(人能輕易規避)的無效重複
  • 具體問題具體分析,發掘有效剪枝方式

字典序存取

  • 即給定排列求序號/給定序號求排列
    • 採用從頭按位固定計算排列總數的方法逐位推導
  • 是否按有效序列壓縮/時間空間權衡
    • 狀態數較小時,直接方式編碼,以空間換時間
    • 狀態數較多/採用直接方式會導致大量空間被無效狀態消耗時,用字典序(其他編碼方式),以時間換空間

相關文章