day 16 算法:回溯法單詞搜索

本題有點複雜,需要結合leetCode來看,只當其中一個答案來看即可,不然會雲裏霧裏。

1. 題目

  1. 單詞搜索二:給定一個二維網格board和一個字典中的單詞列表words,找出所有同時在二位網格和字典中出現的單詞。單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中相鄰單元格式那些水平相鄰或者垂直相鄰的單元格,同一個單元格中的字母不允許在同一個單詞內多次出現。
    https://leetcode-cn.com/problems/word-search-ii/

2. 基本知識

本題還是用的Trie的知識。

3. 算法題解

3.1 單詞搜索二

給定一個二維網格board和一個字典中的單詞列表words,找出所有同時在二位網格和字典中出現的單詞。單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中相鄰單元格式那些水平相鄰或者垂直相鄰的單元格,同一個單元格中的字母不允許在同一個單詞內多次出現。

圖後補

假設所有字母都是小寫,限定範圍,再解題。

回溯法:使用Tried樹輔助

先將所有單詞,分解成字符,組成Tried樹,然後利用回溯法去判斷,如果公共前綴不存在,則該單詞不存在這個網絡列表中。

Trie樹的具體代碼:

public class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    public void insert(String word) {
        TrieNode node = root;

        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.contaionsKey(c)) {
                node.put(c, node);
            }
            node = node.get(c);
            node.setEnd();
        }
    }

    public boolean startWith(String word) {
        TrieNode node = root;

        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (node.contaionsKey(c)) {
                node = node.get(c);
            } else {
                return false;
            }
        }
        if (node != null)
            return true;
        else
            return false;
    }

    public boolean sarch(String word) {

        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (node.contaionsKey(c)) {
                node = node.get(c);
            } else {
                node = null;
                break;
            }
        }
        if (node != null && node.isEnd()) {
            return true;
        } else {
            return false;
        }
    }
}

本題的題解:

List<String> results = new ArrayList<>();

public List<String> findWords(String[] words, char[][] board) {
    Trie trie = new Trie();
    // 生成Tried樹
    for (String s : words) {
        trie.insert(s);
    }
    //記下board的邊界
    int row = board.length;
    int col = board[0].length;
    // 使用一個數組來標記是否 已經使用過該節點
    boolean[][] visted = new boolean[row][col];
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            dfs(board, visted, "", i, j, trie);
        }
    }

    return results;
}

/**
 * 遍歷board,從Tried中查找是否存在,存在則加到列表中,否則不處理
 *
 * @param board  二維字符表格
 * @param visted 是否使用過
 * @param result 結果字符串,初始化爲“”
 * @param row
 * @param col
 * @param trie   字符組成的Tried樹
 */
private void dfs(char[][] board, boolean[][] visted, String result, int row, int col, Trie trie) {
    //遍歷超出範圍,終止
    if (row >= board.length || col >= board[0].length)
        return;
    //組合前綴
    result += board[row][col];
    //成功查詢到內容
    if (trie.sarch(result))
        results.add(result);
    // 無公共前綴
    if (!trie.startWith(result)) return;
    //標記已使用
    visted[row][col] = true;
    //上一行
    dfs(board, visted, result, row - 1, col, trie);
    dfs(board, visted, result, row + 1, col, trie);

    dfs(board, visted, result, row, col - 1, trie);
    dfs(board, visted, result, row, col + 1, trie);

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