lc425

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.

1
2
3
4
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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我之前还没有写过,只知道概念,其结构是有一个26个nullptr的children指针的vector,有子树时那条边的字母对应的children元素从nullptr改为子树地址。另外还有index数组保存该节点子树中所有字符串在原words中对应的index。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class TrieNode {
public:
vector<int> index;
vector<TrieNode*> children;
public:
TrieNode():children(26, nullptr) { }
};
class Solution {
public:
vector<vector<string>> res;
TrieNode* buildTrie(vector<string>& words) {
TrieNode* root = new TrieNode();
TrieNode* node;
for (int j = 0; j < words.size(); j++) {
node = root;
string word = words[j];
for (int i = 0; i < word.length(); i++) {
if (!node -> children[word[i]-'a']) {
TrieNode* new_node = new TrieNode();
node -> children[word[i]-'a'] = new_node;
}
node = node -> children[word[i]-'a'];
node -> index.push_back(j);
}
}
return root;
}
void backtracking(TrieNode* r, int level, vector<string> &square, vector<string> &words) {
if (level >= words[0].length()) {
res.push_back(square);
return;
}
TrieNode* t = r;
for (int i = 0; i < level; i++) {
if (!t->children[square[i][level]-'a']) return;
t = t->children[square[i][level]-'a'];
}
for (auto in:t->index) {
square[level] = words[in];
backtracking(r, level+1, square, words);
square[level] = "";
}
return;
}
vector<vector<string>> wordSquares(vector<string>& words) {
vector<string> square{words.size(), ""};
TrieNode* root = buildTrie(words);
for (auto word: words) {
square[0] = word;
backtracking(root, 1, square, words);
}
return res;
}
};