212. Word SearchII

题目:
Given a 2D board and a list of words from the dictionary, find all words in the board.

Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

For example,
Given words = ["oath","pea","eat","rain"] and board =

[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
Return ["eat","oath"].

解答:
这题我原来是在word search I的基础上,用backtracking来做的,代码如下:

public boolean exist(char[][] board, String word, int i, int j, int pos, boolean[][] visited) {
    if (pos == word.length()) return true;
    if (i < 0 || i > board.length - 1 || j < 0 || j > board[i].length - 1) return false;
    if (visited[i][j] || board[i][j] != word.charAt(pos)) return false;
    
    visited[i][j] = true;
    int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    for (int k = 0; k < dir.length; k++) {
        int x = i + dir[k][0], y = j + dir[k][1];
        if (exist(board, word, x, y, pos + 1, visited)) {
            return true;
        }
    }
    visited[i][j] = false;
    return false;
}

public boolean helper(char[][] board, String word) {
    boolean[][] visited = new boolean[board.length][board[0].length];
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[i].length; j++) {
            if (exist(board, word, i, j, 0, visited)) {
                return true;
            }
        }
    }
    return false;
}

public List<String> findWords(char[][] board, String[] words) {
    List<String> result = new ArrayList<String>();
    if (board == null || board.length == 0 || board[0].length == 0) return result;
 
    for (String word : words) {
        if (helper(board, word)) {
            if (!result.contains(word)) {
                result.add(word);
            }
        }
    }
    
    return result;
}

做完之后,结果运行是对的,但是TLE了,所以肯定是有更好的办法。在TLE的test case里,我看到是当prefix相同时,如果用backtracking那么会不断地扫同一个位置的prefix,非常的冗余,那么怎么把prefix提取出来只扫一次呢?一个很好的办法就是反过来,用trie树先把单词存起来,然后扫board,扫board的时候用trie树中的可能出现的单词作为限制条件,那么当扫到一个trie中结尾存在的单词时,把它存进result中去。代码如下:

class TrieNode {
    TrieNode[] next = new TrieNode[26];
    String word;
}

public TrieNode buildTrie(String[] words) {
    TrieNode root = new TrieNode();
    for (String word : words) {
        TrieNode p = root;
        for (char c : word.toCharArray()) {
            int i = c - 'a';
            if (p.next[i] == null) p.next[i] = new TrieNode();
            p = p.next[i];
        }
        p.word = word;
    }
    return root;
}

public void dfs(List<String> result, char[][] board, TrieNode p, int i, int j) {
    char c = board[i][j];
    if (c == '#' || p.next[c - 'a'] == null) return;
    p = p.next[c - 'a'];
    
    if (p.word != null) {
        result.add(p.word);
        p.word = null; //去重
    }
    
    board[i][j] = '#';
    int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    for (int k = 0; k < dir.length; k++) {
        int x = i + dir[k][0], y = j + dir[k][1];
        if (x < 0 || x > board.length - 1 || y < 0 || y > board[i].length - 1) continue;
        dfs(result, board, p, x, y);
    }
    board[i][j] = c;
}

public List<String> findWords(char[][] board, String[] words) {
    List<String> result = new ArrayList<String>();
    if (board == null || board.length == 0 || board[0].length == 0) return result;
    
    TrieNode root = buildTrie(words);
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[i].length; j++) {
            dfs(result, board, root, i, j);
        }
    }
    return result;
}

199 声望
14 粉丝
0 条评论
推荐阅读
126. Word Ladder II
题目:Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

guoluona阅读 2.5k

Java12的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft63阅读 11.9k

Java8的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft32阅读 24.6k评论 1

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go33阅读 2.5k评论 1

封面图
Java11的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft28阅读 15.4k评论 3

Java5的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft13阅读 20.4k

Java9的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft20阅读 14.5k

199 声望
14 粉丝
宣传栏