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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章