package com.interview.graph; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Date 03/04/2016 * @author Tushar Roy * * Search for dictionary words in the board. * Idea is to use trie for the dictionary which keeps search * very efficient. * * https://leetcode.com/problems/word-search-ii/ */ public class Boggle { public List<String> findWords(char[][] board, String[] words) { Trie t = new Trie(); for (String word : words) { t.insert(word); } StringBuffer buff = new StringBuffer(); Set<String> result = new HashSet<>(); Set<Integer> visited = new HashSet<>(); for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[i].length; j++) { findWordsUtil(board, t, i, j, buff, visited, result, board[0].length); } } return new ArrayList<>(result); } private void findWordsUtil(char[][] board, Trie t , int i, int j, StringBuffer buff, Set<Integer> visited, Set<String> result, int col ) { if (i < 0 || j < 0 || i >= board.length || j >= board[i].length) { return; } int val = i*col + j; if (visited.contains(val)) { return; } buff.append(board[i][j]); String str = buff.toString(); if(!t.startsWith(str)) { buff.deleteCharAt(buff.length() - 1); return; } visited.add(val); if(t.search(str)) { result.add(buff.toString()); } findWordsUtil(board, t, i + 1, j, buff, visited, result, col); findWordsUtil(board, t, i, j + 1, buff, visited, result, col); findWordsUtil(board, t, i, j - 1, buff, visited, result, col); findWordsUtil(board, t, i - 1, j, buff, visited, result, col); buff.deleteCharAt(buff.length() - 1); visited.remove(val); } class TrieNode { TrieNode[] child = new TrieNode[26]; boolean isWord; public TrieNode() { } } class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } // Inserts a word into the trie. public void insert(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = (char)(word.charAt(i) - 'a'); if (current.child[ch] == null) { current.child[ch] = new TrieNode(); } current = current.child[ch]; } current.isWord = true; } // Returns if the word is in the trie. public boolean search(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = (char)(word.charAt(i) - 'a'); if (current.child[ch] == null) { return false; } current = current.child[ch]; } return current.isWord; } // Returns if there is any word in the trie // that starts with the given prefix. public boolean startsWith(String prefix) { TrieNode current = root; for (int i = 0; i < prefix.length(); i++) { char ch = (char)(prefix.charAt(i) - 'a'); if (current.child[ch] == null) { return false; } current = current.child[ch]; } return true; } public void printTrie() { printTrieUtil(root); } private void printTrieUtil(TrieNode root) { if (root == null) { return; } for (int i = 0; i < root.child.length; i++) { if (root.child[i] != null) { System.out.println((char)(i + 'a')); printTrieUtil(root.child[i]); } } } } public static void main(String args[]) { char[][] board = {{'o','a','a','n'},{'e','t','a','e'},{'i','h','k','r'},{'i','f','l','v'}}; String[] words = {"oath","pea","eat","rain"}; Boggle boggle = new Boggle(); List<String> result = boggle.findWords(board, words); result.stream().forEach(s -> System.out.println(s)); } }