#include<vector>
#include<algorithm>
#include<string>
#include<iterator>
class cross_word_db
{
protected:
std::vector<std::vector<size_t> > wordlookups;
std::vector<std::string> words;
//an array that is 26*wordlength long basically a double array.
//...it stores another array of sorted indices (a set in linear memory)
static size_t lookupdex(size_t p,const char c)
{
return p*26+std::tolower(c);
}
public:
template<class Iter>
cross_word_db(Iter b,Iter e):
words(b,e)
{
size_t max_wordlength=0;
for(size_t i=0;i<words.size();i++)
{
if(words[i].size() > max_wordlength)
{
max_wordlength=words[i].size();
}
}//find the longest word
wordlookups.resize(26*max_wordlength);
//build the database...
for(size_t i=0;i<words.size();i++)
{
const std::string& w=words[i];
//for each letter, push that words's index into the correct location.
//this will be in sorted order by default.
for(size_t pos=0;pos<w.size();pos++)
{
wordlookups[lookupdex(pos,w[i])].push_back(i);
}
}
}
//a constraint is a 'position,character' pair
typedef std::pair<std::size_t,char> query_constraint;
//a query takes a list of query_constraints...this could have also been an iterator, but whatever
std::vector<std::string> query(const std::vector<query_constraint>& query) const
{
std::vector<query_constraint>::const_iterator qbegin,qend;
qbegin=query.cbegin();
qend=query.cend();
std::vector<size_t> result=wordlookups[lookupdex(qbegin->first,qbegin->second)];
while((++qbegin) != qend)
{
std::vector<size_t> old_result=result;
const std::vector<size_t>& qlist=wordlookups[lookupdex(qbegin->first,qbegin->second)];
std::vector<size_t>::iterator last=set_intersect(old_result.begin(),old_result.end(),qlist.begin(),qlist.end(),result.begin());
result.resize(last-result.begin());
}
std::vector<std::string> retval(result.size());
for(size_t i=0;i<result.size();i++)
{
retval[i]=words[result[i]];
}
return retval;
}
};