通用解題法——回溯算法(理解+練習)

積累算法經驗,積累解題方法——回溯算法,你必須要掌握的解題方法!

什麼是回溯算法呢?

回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。許多複雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。

簡單的理解就是我們走迷宮的時候,走到一個節點,然後有很多路,選一條路不通則退回該節點走其他路;都走不通再往上一個節點倒退,直到找出迷宮出口。

只是簡單的概念無法真正理解這種算法的應用場景,這裏用一道力扣題來進行講解:

leetcode 79. 單詞搜索

難度中等

題目:給定一個二維網格和一個單詞,找出該單詞是否存在於網格中。
單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母不允許被重複使用。

示例:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]

給定 word = “ABCCED”, 返回 true
給定 word = “SEE”, 返回 true
給定 word = “ABCB”, 返回 false

提示:
board 和 word 中只包含大寫和小寫英文字母。
1 <= board.length <= 200
1 <= board[i].length <= 200
1 <= word.length <= 10^3

來源:力扣(LeetCode)

這道題使用回溯算法就是非常好的解法,在性能上也是非常不錯的。

這裏我們可以將首字母對應的每一個座標都當做我們的迷宮入口,之後上下左右進行尋找,找到則繼續,找不到就往上一級回溯,具體解法如下👇
public class _79_單詞搜索 {
   
    public boolean exist(char[][] board, String word) {
        if(word.length() == 0){
            return false;
        }
        char start = word.charAt(0);
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                if(start != board[i][j]){
                    continue;
                }else{
                    if(find(board, word, 0, i, j, 's')){
                        return true;
                    }else{
                        continue;
                    }
                }
            }
        }
        return false;
    }


    /**
     *
     * @param board
     * @param word
     * @param index   word下標
     * @param x       當前的 board[x][y]
     * @param y       當前的 board[x][y]
     * @param pre      規定了s爲開頭  u爲向上 d爲向下 l爲向左 r爲向右
     *                 把已經經過的路徑中的字母換成0,避免重複,這一趟走完再復原,以免影響其他方向的進行。
     * @return
     */
    private boolean find(char[][] board, String word, int index, int x, int y, char pre){
        //System.out.println("index:" + index + ", " + "x:" + x + ",y:" + y);
        if(index == word.length() - 1 && word.charAt(index) == board[x][y]){
            return true;
        }
        if(index >= word.length() || word.charAt(index) != board[x][y]){
            return false;
        }
        boolean found = false;
        //向上尋找
        if(!found && pre != 'd' && x > 0){
            char tmp = board[x][y];
            board[x][y] = '0';
            found = find(board, word, index + 1, x - 1, y, 'u');
            board[x][y] = tmp;
        }
        //向下尋找
        if(!found && pre != 'u' && x < board.length - 1){
            char tmp = board[x][y];
            board[x][y] = '0';
            found = find(board, word, index + 1, x + 1, y, 'd');
            board[x][y] = tmp;
        }
        //向左尋找
        if(!found && pre != 'r' && y > 0){
            char tmp = board[x][y];
            board[x][y] = '0';
            found = find(board, word, index + 1, x, y - 1, 'l');
            board[x][y] = tmp;
        }
        //向右尋找
        if(!found && pre != 'l' && y < board[0].length - 1){
            char tmp = board[x][y];
            board[x][y] = '0';
            found = find(board, word, index + 1, x, y + 1, 'r');
            board[x][y] = tmp;
        }
        return found;
    }
}

以上! 回溯算法你懂了嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章