Leetcode 425. Word Squares
Problem:
Given a set of words (without duplicates), find all word squares you can build from them.
A sequence of words forms a valid word square if the kth row and column read the exact same string, where 0 ≤ k < max(numRows, numColumns).
For example, the word sequence ["ball","area","lead","lady"]
forms a word square because each word reads the same both horizontally and vertically.
b a l l a r e a l e a d l a d y
Note:
- There are at least 1 and at most 1000 words.
- All words will have the exact same length.
- Word length is at least 1 and at most 5.
- Each word contains only lowercase English alphabet
a-z
.
Example 1:
Input: ["area","lead","wall","lady","ball"] Output: [ [ "wall", "area", "lead", "lady" ], [ "ball", "area", "lead", "lady" ] ] Explanation: The output consists of two word squares. The order of output does not matter (just the order of words in each word square matters).
Example 2:
Input: ["abat","baba","atan","atal"] Output: [ [ "baba", "abat", "baba", "atan" ], [ "baba", "abat", "baba", "atal" ] ] Explanation: The output consists of two word squares. The order of output does not matter (just the order of words in each word square matters).
又是道恐怖的Trie的题目,这道题首先需要创建Trie数据结构,里面有个函数getStartsWith(TrieNode *r)是用DFS的方法获取所有从节点r开始的后缀。下面用Example1说明算法思路,path初始化为长宽均为4的字符串数组,首先遍历所有字符串先放满第一行和第一列,比如:
["wall",
"a ",
"l ",
"l "]
然后开始放第二行和第二列,此时我们需要用getStartsWith(TrieNode *r)函数获取前缀为a的所有后缀组合,并一个个尝试,其中一个结果为:
["wall",
"area",
"le ",
"la "]
然后对于第三行和第三列找到前缀为le的所有后缀组合,以此类推,直到index为5即可。
Code:
1 struct TrieNode{ 2 TrieNode *next[26]; 3 bool isEnd; 4 TrieNode():isEnd(false){ 5 for(int i = 0;i != 26;++i) 6 next[i] = NULL; 7 } 8 }; 9 class Trie{ 10 public: 11 Trie(){ 12 root = new TrieNode(); 13 } 14 void insert(string &word){ 15 TrieNode *current = root; 16 for(int i = 0;i != word.size();++i){ 17 if(current->next[word[i]-'a'] == NULL){ 18 current->next[word[i]-'a'] = new TrieNode(); 19 } 20 current = current->next[word[i]-'a']; 21 } 22 current->isEnd = true; 23 } 24 void dfs(TrieNode *r,string path,vector<string> &result){ 25 if(r->isEnd){ 26 result.push_back(path); 27 return; 28 } 29 for(int i = 0;i != 26;++i){ 30 if(r->next[i] != NULL){ 31 dfs(r->next[i],path+(char)(i+'a'),result); 32 } 33 } 34 } 35 vector<string> getStartsWith(TrieNode *r) { 36 vector<string> result; 37 dfs(r,"",result); 38 return result; 39 } 40 TrieNode *getRoot(){ 41 return root; 42 } 43 private: 44 TrieNode *root; 45 }; 46 class Solution { 47 public: 48 void backtrace(int index,Trie &tree,TrieNode *root,vector<string> &path,vector<vector<string>> &result){ 49 int m = path.size(); 50 if(index == m){ 51 result.push_back(path); 52 return; 53 } 54 TrieNode *current = root; 55 for(int i = 0;i != index;++i){ 56 if(current->next[path[index][i]-'a'] == NULL) 57 return; 58 current = current->next[path[index][i]-'a']; 59 } 60 vector<string> suffix = tree.getStartsWith(current); 61 for(int i = 0;i != suffix.size();++i){ 62 for(int j = index;j != m;++j){ 63 path[index][j] = suffix[i][j-index]; 64 path[j][index] = suffix[i][j-index]; 65 } 66 backtrace(index+1,tree,root,path,result); 67 for(int j = index;j != m;++j){ 68 path[index][j] = ' '; 69 path[j][index] = ' '; 70 } 71 } 72 } 73 vector<vector<string>> wordSquares(vector<string>& words) { 74 Trie tree; 75 for(int i = 0;i != words.size();++i) 76 tree.insert(words[i]); 77 TrieNode *root = tree.getRoot(); 78 int m = words[0].size(); 79 vector<vector<string>> result; 80 vector<string> path(m,string(m,' ')); 81 for(int i = 0;i != words.size();++i){ 82 for(int j = 0;j != m;++j){ 83 path[0][j] = words[i][j]; 84 path[j][0] = words[i][j]; 85 } 86 backtrace(1,tree,root,path,result); 87 for(int j = 0;j != m;++j){ 88 path[0][j] = ' '; 89 path[j][0] = ' '; 90 } 91 } 92 return result; 93 } 94 };