package com.interview.algorithms.tree; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import com.interview.basics.model.trie.Trie; import com.interview.basics.model.trie.TrieNode; import com.interview.utils.Timer; /** * Problem Description: * http://stackoverflow.com/questions/746082/how-to-find-list-of-possible-words-from-a-letter-matrix-boggle-solver * * * @author zouzhile * */ public class BoggleSolver { class State { public final int row, column; // row and column index public final String prefix; // the next prefix equals to (prefix + data[i][j]) public State(int row, int column, String prefix){ this.row = row; this.column = column; this.prefix = prefix; } } private Trie trie; public BoggleSolver(String dictionary) { this.trie = new Trie(); this.buildTrie(dictionary); } public Set<String> findWords(char[][] data){ Set<String> words = new HashSet<String>(); for(int i = 0; i < data.length; i ++) for(int j = 0; j < data[i].length; j ++) words.addAll(this.findWords(data, i, j)); return words; } private Set<String> findWords(char[][] data, int i, int j){ Set<String> words = new HashSet<String>(); List<State> queue = new ArrayList<State>(); if(this.isInsideBound(data, i, j)) queue.add(new State(i, j, "")); while(queue.size() > 0) { State state = queue.remove(0); String prefix = state.prefix + data[state.row][state.column]; TrieNode matchNode = this.trie.match(prefix); if(matchNode != null) { List<State> states = this.getStatesByAdjacentChars(data, state.row, state.column, prefix); queue.addAll(states); if(matchNode.isWord() && prefix.length() >= 3) { words.add(prefix); } } } return words; } private List<State> getStatesByAdjacentChars(char[][] data, int currentRow, int currentColumn, String prefix){ List<State> states = new ArrayList<State>(); for(int rowDelta = -1; rowDelta <= 1; rowDelta ++) for(int columnDelta = -1; columnDelta <= 1; columnDelta ++) { int newRow = currentRow + rowDelta; int newColumn = currentColumn + columnDelta; if(this.isInsideBound(data, newRow, newColumn)) states.add(new State(newRow, newColumn, prefix)); } return states; } private boolean isInsideBound(char[][] data, int i, int j){ boolean inbound = (i >= 0 && i < data.length) && (j >= 0 && j < data[i].length); return inbound; } private void buildTrie(String dictionary){ BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(dictionary)); String line = null; while( (line = reader.readLine()) != null) { String word = line.trim().toLowerCase(); this.trie.addWord(word); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(reader != null) try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * @param args */ public static void main(String[] args) { String array = "djhi,klps,yeut,eorn"; //String array = "fxie,amlo,ewbx,astu"; String[] rows = array.split(","); int rowsCount = rows.length; int columnCount = rows[0].length(); char[][] data = new char[rowsCount][columnCount]; for(int i = 0; i < rowsCount; i ++) for(int j = 0; j < columnCount; j ++) data[i][j] = rows[i].charAt(j); Timer timer = new Timer(); timer.start(); BoggleSolver solver = new BoggleSolver("./documents/dictionary"); timer.stop(); System.out.println("Trie build took " + timer); timer.start(); Set<String> words = solver.findWords(data); timer.stop(); System.out.println("Word binarysearch took " + timer); TreeSet<String> sortedWords = new TreeSet<String>(); sortedWords.addAll(words); int count = 0; System.out.println(); for(String word : sortedWords) { System.out.print(word + " "); count ++; if(count % 10 == 0) System.out.println(); } } }