Description
给出一个总字符个数大小不超过1,000,000的字典(这个字典的单词顺序不为字典序)和不超过1000个长度不超过1000的前缀,输出字典中匹配该前缀,字典序为K_i的单词在字典中的位置。
所有单词都为小写字母。
Input Format
第一行: 两个整数N,M,分别表示字典中的单词个数和需要查询的前缀数。
接下来N行;每行一个字符串,表示字典中的单词。
接下来M行,每行一个K_i, P_i, P_i表示查询的前缀,K_i表示满足这个前缀在字典序中的位置。
Output Format
M行整数,表示符合条件的单词在字典中的位置。如果没有单词满足要求,输出-1
样例解释,符合前缀'a'的单词有{'az', 'ay'},按字典序排序为{'ay', 'az'},字典序第2的是az,在字典的第一个位置。
Input Sample
3 2
az
ay
b
2 a
3 aOutput Sample
1
-1

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MaxN = 26;
//单词的结构
struct Word
{
char word[100];//单词的内容
int word_len;//单词的长度
int ori_id;//单词的原始ID
};
Word dictionary[1000000];//存储字典 后来会排成字典序
//树的节点
struct TrieNode
{
bool isEnd; //是否是一个单词的结尾字符
int sonCount; //子节点的个数
TrieNode* son[MaxN];//子节点指针列表 最多只有26个
int id;//以此节点字符为结尾的单词 在排序后的字典中的位置
TrieNode(){
isEnd = false;
sonCount = 0;
id = -1;
for (int i = 0; i < MaxN; ++i)
son[i] = NULL;
}
};
TrieNode* stack[1000000] = {0};//用于DFS的堆栈
TrieNode* root;//根节点 代表整个字典树
//插入一个词 给出词的内容 词的长度 以及 词在单词列表中的位置
void insert(char* word, int len, int id){
TrieNode* curNode = root;//以根节点为起点
//cout<<root->sonCount<<endl;
for (int i = 0; i < len; ++i)
{
//判断word[i]是否在curNode的子节点列表里
int index = word[i]-'a'; //index 0~25
if(curNode->son[index]==NULL){//没有此字符
curNode->son[index] = new TrieNode();
//个数加一
curNode->sonCount++;
}
if(i==len-1){//单词的结尾
curNode->son[index]->isEnd = true;
curNode->son[index]->id = id;
}
curNode = curNode->son[index];
}
}
bool cmp_int (const int& a, const int& b){
return a < b;
}
//字典序排序
bool cmp_word(const Word& a, const Word& b){
int todo = a.word_len < b.word_len ? a.word_len : b.word_len;
for (int i = 0; i < todo; ++i)
{
if(a.word[i]==b.word[i])
continue;
return a.word[i] < b.word[i];
}
//此时还未return说明两个单词互相包含 把少的那个放在前面
return a.word_len < b.word_len;
}
//根据前缀查询 第cnt个单词 返回在字典中的id
int find(int cnt, char* prefix , int len){
TrieNode* curNode = root;
for (int i = 0; i < len; ++i)
{
int cid = prefix[i]-'a';
if(curNode->son[cid] != NULL){
curNode = curNode->son[cid];
}
}
//现在已经找到了前缀的最后一个字符的节点
int top = 0;
stack[top++] = curNode;
//DFS去找第一个该前缀的词
while(top > 0){
TrieNode* toCheck = stack[--top];
if(toCheck->isEnd){
//立刻返回
return toCheck->id;
}else{
int haveAdded = 0;
for (int i = MaxN-1; i >=0 ; --i)
{
if(toCheck->son[i] != NULL){
haveAdded++;
stack[top++] = toCheck->son[i];
if(haveAdded==toCheck->sonCount)
break;
}
}
}
}
return -1;
}
//判断单词word是否是以prefix为前缀的
bool isIn(Word& word, char* prefix , int len){
if(word.word_len < len)
return false;
for(int i=0; i < len; i++){
if(word.word[i] != prefix[i])
return false;
}
return true;
}
int main(int argc, char const *argv[])
{
int N,M;
cin>>N>>M;
root = new TrieNode();//初始化根节点
for (int i = 1; i <= N; ++i)
{
scanf("%s",dictionary[i].word);
dictionary[i].word_len = strlen(dictionary[i].word);
dictionary[i].ori_id = i;
}
sort(dictionary+1, dictionary+N+1, cmp_word);
for (int i = 1; i <= N; ++i)
insert(dictionary[i].word, dictionary[i].word_len, i);
char pre[1000+10];
for (int i = 0; i < M; ++i)
{
int k = 0;
scanf("%d %s",&k,pre);
//找到以该前缀为前缀的第一个单词的排序后ID + k-1 判断是否是
int first = find(k,pre,strlen(pre));
if(first+k-1 <=N and isIn(dictionary[first+k-1],pre,strlen(pre))){
cout<<dictionary[first+k-1].ori_id<<endl;
}else
cout<<-1<<endl;
}
return 0;
}
/*
4 2
ad
as
ase
asfg
2 as
1 ad
*/Trie+字典序优化
标程如下:


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int n, m;
vector< pair<string, int> > dict;
//判断word是否含有pref前缀 果然stl好快
bool match(string& pref, string& word) {
if (pref.size() > word.size()) return false;
return word.substr(0, pref.size()) == pref;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
string s;
cin >> s;
dict.push_back(make_pair(s, i));//pair的单词和id
}
//排字典序 因为string有重载的大于号 所以不用加入函数
sort(dict.begin(), dict.end());
for (int i = 0; i < m; i++) {
int k;
string pref;
cin >> k >> pref;
k--;//因为id从0开始
//stl的二分查找
int pos = lower_bound(dict.begin(), dict.end(), make_pair(pref, 0)) - dict.begin();
// Ignore whether pos even matches at all
int poss = pos + k;
if (poss < dict.size() && match(pref, dict[poss].first)) {
cout << dict[poss].second + 1 << '\n';
} else {
cout << -1 << '\n';
}
}
}STL标程
















