您将获得一个包含3个字母单词的字典,并且必须找到3x3的矩阵,这样每行,列和对角线在字典中形成一个单词。字典中的单词已排序,您可以假设O(1)时间从字典中检索单词。
这被问到Facebook面试问题。
答案 0 :(得分:5)
我的方法是首先过滤字典以创建两个新词典:第一个包含单词的所有单个字母前缀(其中可能有26个),第二个包含单词的所有双字母前缀(其中有因为没有单词以BB开头,所以少于26 ^ 2。
从词典中选择一个单词,将其命名为X
。这将是矩阵的第一行。
使用您提供的方便列表,检查X1
,X2
,X3
是否都是有效的单字母前缀。如果是,继续第3步;否则回到第1步。
从词典中选择一个单词,将其命名为Y
。这将是矩阵的第二行。
使用您提供的方便列表检查X1 Y1
,X2 Y2
,X3 Y3
是否都是有效的双字母前缀。如果是,继续第5步;否则回到第3步。如果这是字典中的最后一个字,那么一直回到第1步。
从词典中选择一个单词,将其命名为Z
。这将是矩阵的第三行。
检查X1 Y1 Z1
,X2 Y2 Z2
,X3 Y3 Z3
是字典中的所有字词。如果他们是,恭喜,你已经做到了!否则返回步骤5.如果这是字典中的最后一个字,那么一直回到第3步。
我在Maple中对此进行了编码,效果相当不错。我让它运行以找到所有这些矩阵,事实证明,由于内存溢出,有足够的崩溃Maple。
答案 1 :(得分:1)
您的评论建议您也在寻找回溯解决方案,但效率不高,但解决了这个问题。伪代码:
solve(dictionary,matrix):
if matrix is full:
if validate(dictionary,matrix) == true:
return true
else:
return false
for each word in dictionary:
dictionary -= word
matrix.add(word)
if solve(dictionary,matrix) == true:
return true
else:
dictionary += word
matrix.removeLast()
return false //no solution for this matrix.
在上面的伪代码中,matrix.add()
在第一个非占用行中添加给定的单词。 matrix.remove()
删除最后占用的行,validate()
检查解决方案是否合法。
激活:solve(dictionary,empty_matrix)
,如果算法产生true,则有一个解决方案,输入矩阵将包含它,否则它将产生错误。
以上伪代码以指数时间运行!这是非常无效的。但是,由于此问题类似于(*)填字游戏问题,即NP-Complete,因此它可能是您的最佳选择。
(*)原始的填字游戏问题没有这个问题所具有的对角线条件,当然更为通用:nxm矩阵,不仅仅是3x3。虽然问题是相似的,但是减少并没有出现在我脑海中,如果存在,我会很高兴看到一个。
答案 2 :(得分:1)
一些JavaScript来说明。
//setup a test dictionary
var dict = [
"MAD",
"FAD",
"CAT",
"ADD",
"DOG",
"MOD",
"FAM",
"ADA",
"DDD",
"FDD"
];
for(var i=0; i<dict.length; i++)
dict[dict[i]]=true;
// functions
function find(dict) {
for(var x=0; x<dict.length; x++) {
for(var y=x+1; y<dict.length; y++) {
for(var z=y+1; z<dict.length; z++) {
var a=dict[x];
var b=dict[y];
var c=dict[z];
if(valid(dict,a,b,c)) return [a,b,c];
if(valid(dict,a,c,b)) return [a,c,b];
if(valid(dict,b,a,c)) return [b,a,c];
if(valid(dict,b,c,a)) return [b,c,a];
if(valid(dict,c,a,b)) return [c,a,b];
if(valid(dict,c,b,a)) return [c,b,a];
}
}
}
return null;
}
function valid(dict, row1, row2, row3) {
var words = [];
words.push(row1.charAt(0)+row2.charAt(0)+row3.charAt(0));
words.push(row1.charAt(1)+row2.charAt(1)+row3.charAt(1));
words.push(row1.charAt(2)+row2.charAt(2)+row3.charAt(2));
words.push(row1.charAt(0)+row2.charAt(1)+row3.charAt(2));
words.push(row3.charAt(0)+row2.charAt(1)+row1.charAt(2));
for(var x=0; x<words.length; x++)
if(dict[words[x]] == null) return false;
return true;
}
//test
find(dict);
答案 3 :(得分:1)
我不一定在寻找回溯解决方案。它只是让我觉得可以使用反向跟踪,但解决方案有点复杂。但是我们可以使用分支和修剪来缩短蛮力技术。
首先我们将选择一个字符串作为最顶行,而不是在矩阵中搜索所有可能的组合。使用第一个字符,我们为第一列找到合适的竞争者。现在使用列字符串的2和3个字符,我们将找到适合第二和第三行的单词。
要有效地找到以特定字符开头的单词,我们将使用基数排序,以便所有以特定字符开头的单词都存储在同一个列表中。当我们选择矩阵的第二行和第三行时,我们有一个完整的矩阵。\
我们将检查矩阵是否有效,方法是检查第2列和第3列,并将对角线形成字典中的单词。
当我们发现矩阵有效时,我们可以停止。这有助于减少一些可能的组合。但是我觉得可以通过考虑另一行或列来进一步优化,但是这会有点复杂。我在下面发布了一个工作代码。
请不要介意这些函数的命名,因为我是业余编码器,我通常不会给出非常合适的名称,并且代码的某些部分是硬编码为3个字母的单词。
#include<iostream>
#include<string>
#include<algorithm>
#include<fstream>
#include<vector>
#include<list>
#include<set>
using namespace std;
// This will contain the list of the words read from the
// input file
list<string> words[26];
// This will contain the output matrix
string out[3];
// This function finds whether the string exits
// in the given dictionary, it searches based on the
// first character of the string
bool findString(string in)
{
list<string> strings = words[(int)(in[0]-'a')];
list<string>:: iterator p;
p = find(strings.begin(),strings.end(),in);
if(p!=strings.end())
return true;
}
// Since we have already chosen valid strings for all the rows
// and first column we just need to check the diagnol and the
// 2 and 3rd column
bool checkMatrix()
{
// Diagnol 1
string d1;
d1.push_back(out[0][0]);
d1.push_back(out[1][1]);
d1.push_back(out[2][2]);
if(!(findString(d1)))
return false;
// Diagnol 2
string d2;
d2.push_back(out[0][0]);
d2.push_back(out[1][1]);
d2.push_back(out[2][2]);
if(!(findString(d2)))
return false;
// Column 2
string c2;
c2.push_back(out[0][1]);
c2.push_back(out[1][1]);
c2.push_back(out[2][1]);
if(!(findString(c2)))
return false;
// Column 3
string c3;
c3.push_back(out[0][2]);
c3.push_back(out[1][2]);
c3.push_back(out[2][2]);
if(!(findString(c3)))
return false;
else
return true;
// If all match then return true
}
// It finds all the strings begining with a particular character
list<string> findAll(int i)
{
// It will contain the possible strings
list<string> possible;
list<string>:: iterator it;
it = words[i].begin();
while(it!=words[i].end())
{
possible.push_back(*it);
it++;
}
return possible;
}
// It is the function which is called on each string in the dictionary
bool findMatrix(string in)
{
// contains the current set of strings
set<string> current;
// set the first row as the input string
out[0]=in;
current.insert(in);
// find out the character for the column
char first = out[0][0];
// find possible strings for the column
list<string> col1 = findAll((int)(first-'a'));
list<string>::iterator it;
for(it = col1.begin();it!=col1.end();it++)
{
// If this string is not in the current set
if(current.find(*it) == current.end())
{
// Insert the string in the set of current strings
current.insert(*it);
// The characters for second and third rows
char second = (*it)[1];
char third = (*it)[2];
// find the possible row contenders using the column string
list<string> secondRow = findAll((int)(second-'a'));
list<string> thirdRow = findAll((int)(third-'a'));
// Iterators
list<string>::iterator it1;
list<string>::iterator it2;
for(it1= secondRow.begin();it1!=secondRow.end();it1++)
{
// If this string is not in the current set
if(current.find(*it1) == current.end())
{
// Use it as the string for row 2 and insert in the current set
current.insert(*it1);
for(it2 = thirdRow.begin();it2!=thirdRow.end();it2++)
{
// If this string is not in the current set
if(current.find(*it2) == current.end())
{
// Insert it in the current set and use it as Row 3
current.insert(*it2);
out[1]=*it1;
out[2]=*it2;
// Check ifthe matrix is a valid matrix
bool result = checkMatrix();
// if yes the return true
if(result == true)
return result;
// If not then remove the row 3 string from current set
current.erase(*it2);
}
}
// Remove the row 2 string from current set
current.erase(*it1);
}
}
// Remove the row 1 string from current set
current.erase(*it);
}
}
// If we come out of these 3 loops then it means there was no
// possible match for this string
return false;
}
int main()
{
const char* file = "input.txt";
ifstream inFile(file);
string word;
// Read the words and store them in array of lists
// Basically radix sort them based on their first character
// so all the words with 'a' appear in the same list
// i.e. words[0]
if(inFile.is_open())
{
while(inFile.good())
{
inFile >> word;
if(word[0] >= 'a' && word[0] <= 'z')
{
int index1 = word[0]-'a';
words[index1].push_back(word);
}
}
}
else
cout<<"The file could not be opened"<<endl;
// Call the findMatrix function for each string in the list and
// stop when a true value is returned
int i;
for(i=0;i < 26;i++)
{
it = words[i].begin();
while(it!=words[i].end())
{
if(findMatrix(*it))
{
// Output the matrix
for(int j=0;j<3;j++)
cout<<out[j]<<endl;
// break out of both the loops
i=27;
break;
}
it++;
}
}
// If i ==26 then the loop ran the whole time and no break was
// called which means no match was found
if(i==26)
cout<<"Matrix does not exist"<<endl;
system("pause");
return 0;
}
我已经在一小组字符串上测试了代码并且工作正常。