package com.interview.books.ccinterview;
import com.interview.design.questions.DZ22_Tries;
import com.interview.utils.ctci.AssortedMethods;
import java.util.ArrayList;
/**
* Created_By: stefanie
* Date: 15-2-8
* Time: 下午6:03
*/
public class CC38_WordPuzzleII {
static class Puzzle {
// Puzzle data.
public int rows;
public int cols;
public char[][] puzzle;
public Puzzle(int rows) {
this.rows = rows;
}
public Puzzle(char[][] letters) {
this.rows = letters.length;
this.cols = letters[0].length;
puzzle = letters;
}
//check if every column is a valid word
public boolean isComplete(int row, int col, WordGroup groupList) {
// Check if we have formed a complete rectangle.
if (cols == col) {
// Check if each column is a word in the dictionary.
for (int i = 0; i < row; i++) {
String rowWord = String.valueOf(puzzle[i]);
if (!groupList.containsWord(rowWord)) {
return false; // Invalid rectangle.
}
}
return true; // Valid Puzzle!
}
return false;
}
//check if every column is a valid prefix
public boolean isPartialOK(DZ22_Tries trie) {
if (cols == 0) {
return true;
}
for (int i = 0; i < cols; i++) {
String rowWord = String.valueOf(puzzle[i]);
if (!trie.isPrefix(rowWord)) {
return false; // Invalid rectangle.
}
}
return true;
}
//add a new string in a new row and generate a new Puzzle
public Puzzle append(String s) {
if (s.length() == rows) {
char temp[][] = new char[rows][cols + 1];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
temp[i][j] = puzzle[i][j];
}
}
for(int i = 0; i < rows; i++) temp[i][cols] = s.charAt(i);
return new Puzzle(temp);
}
return null;
}
/* Print the rectangle out, row by row. */
public void print() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
System.out.print(puzzle[i][j]);
}
System.out.println(" ");
}
}
}
static class WordGroup {
private DZ22_Tries trie = new DZ22_Tries();
private ArrayList<String> group = new ArrayList<String>();
public boolean containsWord(String s) {
return trie.isWord(s);
}
public void addWord (String s) {
group.add(s);
trie.add(s);
}
public int length() {
return group.size();
}
public String getWord(int i) {
return group.get(i);
}
public ArrayList<String> getWords(){
return group;
}
public static WordGroup[] createWordGroups(String[] list) {
WordGroup[] groupList;
int maxWordLength = 0;
// Find out the rows of the longest word
for (int i = 0; i < list.length; i++) {
if (list[i].length() > maxWordLength) {
maxWordLength = list[i].length();
}
}
groupList = new WordGroup[maxWordLength];
for (int i = 0; i < list.length; i++) {
/* We do wordLength - 1 instead of just wordLength since this is used as
* an index and no words are of rows 0 */
int wordLength = list[i].length() - 1;
if (groupList[wordLength] == null) {
groupList[wordLength] = new WordGroup();
}
groupList[wordLength].addWord(list[i]);
}
return groupList;
}
}
static class PuzzleGenerator{
private int maxWordLength;
private WordGroup[] wordGroups;
public PuzzleGenerator(String[] dict) {
wordGroups = WordGroup.createWordGroups(dict);
maxWordLength = wordGroups.length;
}
public Puzzle findMaxPuzzle() {
// The dimensions of the largest possible rectangle.
for(int rows = maxWordLength; rows > 0; rows--){
for(int cols = maxWordLength; cols >= rows; cols--){
Puzzle puzzle = makePuzzle(rows, cols);
if (puzzle != null) {
return puzzle;
}
}
}
return null;
}
private Puzzle makePuzzle(int rows, int cols) {
if (wordGroups[rows - 1] == null || wordGroups[rows - 1] == null) {
return null;
}
return makePartialPuzzle(rows, cols, new Puzzle(rows), 0);
}
private Puzzle makePartialPuzzle(int rows, int cols, Puzzle puzzle, int wordIdx) {
// Check if we have formed a complete puzzle by seeing if each column
// is in the dictionary
if (puzzle.cols == cols) {
if (puzzle.isComplete(rows, cols, wordGroups[rows - 1])) {
return puzzle;
} else {
return null;
}
}
// If the puzzle is not empty, validate that each column is a
// substring of a word of rows h in the dictionary using the
// trie of words of rows h.
if (!puzzle.isPartialOK(wordGroups[rows - 1].trie)) {
return null;
}
//backtracing to add words in puzzle
for (int i = wordIdx; i < wordGroups[rows - 1].length(); i++) {
String word = wordGroups[rows - 1].getWord(i);
Puzzle nextPuzzle = makePartialPuzzle(rows, cols, puzzle.append(word), i+1);
if (nextPuzzle != null) {
return nextPuzzle;
}
}
return null;
}
}
public static void main(String[] args) {
PuzzleGenerator generator = new PuzzleGenerator(AssortedMethods.getListOfWords());
Puzzle puzzle = generator.findMaxPuzzle();
if (puzzle != null) {
puzzle.print();
} else {
System.out.println ("No rectangle exists");
}
}
}