【40講系列9】回溯算法、剪枝


一、理論

  1)首先,使用回溯算法關鍵是,將問題轉化為 【樹形問題】

  2)回溯的關鍵點: for循環、 遞歸

   for循環的作用在於另尋它路,可以逐個選擇當前節點下的所有可能往下走下去的分支路徑。

   遞歸可以實現一條路走到黑和回退一步,把遞歸放在for循環內部,那么for每一次的循環,都在給出一個路徑后進入遞歸,繼續往下走。

  3)因此,for循環和遞歸配合可以實現回溯,所以DFS是最典型的回溯法的應用。

 

  理論詳解及分類經典習題:回溯算法入門級詳解 + 練習(持續更新)

二、典型例題

☆☆☆☆①:如何使N個皇后彼此之間不能相互攻擊(LC51、LC52)

思路:如果在(i,j)處放置了一個皇后,那么

1. 整個第 i 行的位置都不能放置;

2. 整個第 j 列的位置都不能放置。

3. 如果位置(a,b)滿足|a-i|==|b-j|,說明(a,b)和(i,j)處在同一條斜線上,也不能放置。

class Solution {
    // LeetCode 52
    // 參考左神,還可以進一步使用位運算加速
    int res = 0;
    public int totalNQueens(int n) {
        if (n < 1) return 0;
        int[] record = new int[n]; // record[index]表示第index行皇后所在的列數
        help(record,0,n);
        return res;
    }
    private void help(int[] record,int index, int n){
        if (index == n){ // 此時已經確定一種情況
            res++;
            return;
        }
        for (int j = 0; j < n; j++) {
            if (isVaild(record,index,j)){
                record[index] = j;
                help(record,index+1,n);
            }
        }
    }
    private boolean isVaild(int[] record,int index, int j){
        for (int k = 0; k < index; k++) {
            if (record[k] == j || Math.abs(k - index) == Math.abs(record[k] - j)){
                return false;
            }
        }
        return true;
    }
}

Note:本題的最優解是使用位運算加速,見【40講系列11】位運算

 

②:判斷數獨是否有效(LC36)

M

☆☆☆☆③:解數獨(LeetCode37. 解數獨

 

三、擴展例題

第一組(樹形問題):LeetCode17. 電話號碼的字母組合LeetCode93. 復原IP地址LeetCode131. 分割回文串

第二組(排列問題):LeetCode46. 全排列LeetCode47. 全排列 II

第三組(組合問題):LeetCode77. 組合LeetCode39. 組合總和LeetCode40. 組合總和 IILeetCode216. 組合總和 IIILeetCode78. 子集LeetCode90. 子集 IILeetCode401. 二進制手表

第四組(二維平面上的回溯):LeetCode79. 單詞搜索

第五組(Flood Fill):LeetCode200. 島嶼數量LeetCode130. 被圍繞的區域LeetCode417. 太平洋大西洋水流問題

第六組(游戲問題):LeetCode51. N 皇后LeetCode52. N皇后 IILeetCode37. 解數獨

四、綜合練習

題型一:排列、組合、子集相關問題

  Note:理解為什么有時候用visited數組,有時候設置搜索起點start

  • LeetCode46. 全排列
  • LeetCode47. 全排列2:思考為什么造成了重復,如何在搜索之前就判斷這一支會產生重復;
  • LeetCode39. 組合總和
  • LeetCode40. 組合總和2
  • LeetCode77. 組合
  • LeetCode78. 子集
  • LeetCode90. 子集2 : 剪枝技巧同 47 題、39 題、40 題;
  • LeetCode60. 第k個排列 : 利用了剪枝的思想,減去了大量枝葉,直接來到需要的葉子結點;
  • LeetCode93. 復原IP地址

題型二:Flood Fill

  Note:以下問題都不建議修改輸入數據,設置visited數組是標准做法。

  • LeetCode733. 圖像渲染
  • LeetCode200. 島嶼數量
  • LeetCode130. 被圍繞的區域
  • LeetCode79. 單詞搜素

題型三:字符串中的回溯問題

  Note: 字符串問題的特殊之處在於,字符串的拼接會生成新對象,因此沒有顯示【回溯】的過程。但如果用StringBuilder拼接字符串則需要回溯。

  • LeetCode17. 電話號碼的字母組合
  • LeetCode784. 字母大小寫全排列
  • LeetCode22. 括號生成:本題也可用BFS,可以通過本題理解為什么回溯算法都是DFS,並且都用遞歸來寫。

題型四:游戲問題

  • LeetCode51. N皇后:其實就是全排列問題,注意設計清楚狀態變量,在遍歷的時候需要記住一些信息,空間換時間;
  • LeetCode37. 解數獨:思路同N皇后問題
  • LeetCode488. 祖瑪游戲
  • LeetCode529. 掃雷游戲

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM