212. 单词搜索 II
题目:
思路:
【1】常规的模拟方法(这种直接就超时了)
【2】回溯 + 字典树
【3】删除被匹配的单词
代码展示:
【1】常规的模拟方法(这种直接就超时了)
class Solution { public List<String> findWords(char[][] board, String[] words) { boolean[] flag = new boolean[words.length]; int row = board.length, col = board[0].length; boolean[][] boardFlag; for (int i = 0; i < row; i++){ for (int j = 0; j < col; j++){ for (int k = 0; k < words.length; k++){ if (!flag[k]){ boardFlag = new boolean[row][col]; flag[k] = checkString(board,i,j,boardFlag,words[k],0); } } } } ArrayList<String> res = new ArrayList<>(); for (int k = 0; k < words.length; k++){ if (flag[k]) res.add(words[k]); } return res; } private boolean checkString(char[][] board,int row,int col,boolean[][] boardFlag,String word,int k){ if (board[row][col] != word.charAt(k) || boardFlag[row][col]) return false; if (k >= word.length()-1) return true; boardFlag[row][col] = true; // 上下左右 int[][] dire = new int[][]{{-1,0},{1,0},{0,-1},{0,1}}; int rowBord = board.length, colBord = board[0].length; boolean res = false; for (int[] d : dire){ int newRow = row+d[0]; int newCol = col+d[1]; // 必须要在边界值内才行,不然会数组溢出 if (newRow >= 0 && newCol>=0 && newRow < rowBord && newCol< colBord){ boardFlag[row][col] = true; res = res || checkString(board,newRow,newCol,boardFlag,word,k+1); // 这里要对标记的走过位置进行复原 boardFlag[row][col] = false; } if (res) return true; } return res; } }
【2】回溯 + 字典树
//时间548 ms 击败 46.4% //内存42.8 MB 击败 56.76% class Solution { int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public List<String> findWords(char[][] board, String[] words) { Trie trie = new Trie(); for (String word : words) { trie.insert(word); } Set<String> ans = new HashSet<String>(); for (int i = 0; i < board.length; ++i) { for (int j = 0; j < board[0].length; ++j) { dfs(board, trie, i, j, ans); } } return new ArrayList<String>(ans); } public void dfs(char[][] board, Trie now, int i1, int j1, Set<String> ans) { if (!now.children.containsKey(board[i1][j1])) { return; } char ch = board[i1][j1]; now = now.children.get(ch); if (!"".equals(now.word)) { ans.add(now.word); } board[i1][j1] = '#'; for (int[] dir : dirs) { int i2 = i1 + dir[0], j2 = j1 + dir[1]; if (i2 >= 0 && i2 < board.length && j2 >= 0 && j2 < board[0].length) { dfs(board, now, i2, j2, ans); } } board[i1][j1] = ch; } } class Trie { String word; Map<Character, Trie> children; boolean isWord; public Trie() { this.word = ""; this.children = new HashMap<Character, Trie>(); } public void insert(String word) { Trie cur = this; for (int i = 0; i < word.length(); ++i) { char c = word.charAt(i); if (!cur.children.containsKey(c)) { cur.children.put(c, new Trie()); } cur = cur.children.get(c); } cur.word = word; } }
【3】删除被匹配的单词
//时间94 ms 击败 87.93% //内存42.9 MB 击败 53.38% class Solution { int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public List<String> findWords(char[][] board, String[] words) { Trie trie = new Trie(); for (String word : words) { trie.insert(word); } Set<String> ans = new HashSet<String>(); for (int i = 0; i < board.length; ++i) { for (int j = 0; j < board[0].length; ++j) { dfs(board, trie, i, j, ans); } } return new ArrayList<String>(ans); } public void dfs(char[][] board, Trie now, int i1, int j1, Set<String> ans) { if (!now.children.containsKey(board[i1][j1])) { return; } char ch = board[i1][j1]; Trie nxt = now.children.get(ch); if (!"".equals(nxt.word)) { ans.add(nxt.word); nxt.word = ""; } if (!nxt.children.isEmpty()) { board[i1][j1] = '#'; for (int[] dir : dirs) { int i2 = i1 + dir[0], j2 = j1 + dir[1]; if (i2 >= 0 && i2 < board.length && j2 >= 0 && j2 < board[0].length) { dfs(board, nxt, i2, j2, ans); } } board[i1][j1] = ch; } if (nxt.children.isEmpty()) { now.children.remove(ch); } } } class Trie { String word; Map<Character, Trie> children; boolean isWord; public Trie() { this.word = ""; this.children = new HashMap<Character, Trie>(); } public void insert(String word) { Trie cur = this; for (int i = 0; i < word.length(); ++i) { char c = word.charAt(i); if (!cur.children.containsKey(c)) { cur.children.put(c, new Trie()); } cur = cur.children.get(c); } cur.word = word; } }