我正在构建一个以电话号码作为输入的程序。然后应检查是否已存在电话号码,该电话号码是我们新号码中的前缀。 例如:
Input:
555 //This is okay
5556888 //This is not okay because 555 is a registered number
556888 //this is okay
5568889 // Not okay
希望你明白我的目标。
我已经实现了两个功能:
包含 那应该检查数字或前缀是否已经存在。
bool PrefixStringSet::contains(string s)
{
NodePtr temp = root;
for ( int i = 0; i < s.size(); i++)
{
if(temp->children[s[i] - '0'] == NULL)
{
return false;
}
temp = temp->children[s[i] - '0'];
}
return true;
}
插入
bool PrefixStringSet::insert(string s)
{
if(contains(s) == true)
{
return false;
}
NodePtr temp = root;
for (int i = 0; i < s.size(); i++)
{
int number = (int)s[i] - (int)'0';
if(temp->children[number] == NULL)
{
temp->children[number] = new TrieNode;
temp = temp->children[number];
}
}
return true;
}
现在只包含支票,如果号码已经注册的话。我无法弄清楚检查前缀是否已经是一个数字的好方法。 我应该在contains或者插入函数中实现它(也许有一个循环遍历每个前缀,从第一个数字开始?)
任何帮助表示感谢。
主要
int main()
{
PrefixStringSet Phonenumber;
int HowManyPhoneNumbers;
cin >> HowManyPhoneNumbers;
for(int i = 0 ; i<HowManyPhoneNumbers ; i++)
{
string temp;
cin >> temp;
if(Phonenumber.insert(temp) == true)
{
cout << "Yes" << endl;
}
else
{
cout << "NO" <<endl;
}
}
return 0;
}
修改 插入:
bool PrefixStringSet::insert(string s)
{
if(contains(s) == true)
{
return false;
}
NodePtr temp = root;
for (int i = 0; i < s.size(); i++)
{
int number = (int)s[i] - (int)'0';
if(temp->children[number] == NULL)
{
temp->children[number] = new TrieNode;
}
temp = temp->children[number];
}
return true;
}
Contains:
bool PrefixStringSet::contains(string s)
{
NodePtr temp = root;
for ( int i = 0; i < s.size(); i++)
{
if(temp->is_leaf())
{
return false;
}
if(temp->children[s[i] - '0'] == NULL)
{
return false;
}
temp = temp->children[s[i] - '0'];
}
return true;
}
input:
911
YES
9111 /Not working
Yes
91 //Working
NO
EDIT2:
bool PrefixStringSet::contains(string s)
{
NodePtr temp = root;
for ( int i = 0; i < s.size(); i++)
{
if(temp->is_leaf())
{
return false;
}
if (temp !=root && temp->is_leaf())
{
return true;
}
if(temp->children[s[i] - '0'] == NULL)
{
return false;
}
temp = temp->children[s[i] - '0'];
}
return true;
}
答案 0 :(得分:2)
在PrefixStringSet::contains(string s)
if(temp->children[s[i] - '0'] == NULL)
{
return false;
}
不应直接返回false
,而应检查temp
是否包含任何非NULL子项。
也就是说,
if(temp->children[s[i] - '0'] == NULL)
{
return (temp != root && temp->is_leaf());
}
因为如果temp
根本没有孩子,那么字符串s
的前缀已经存在。
修改:检查temp != root
以避免陷入空洞的行为。
TrieNode::hasAnyChild()
的最有效实施取决于TrieNode::children
的存储方式,您未在问题陈述中显示。如果你的trie只接受十进制数字,那么简单地通过所有的孩子应该足够好。
顺便提一句,在PrefixStringSet::insert(string s)
int number = (int)s[i] - (int)'0';
if(temp->children[number] == NULL)
{
temp->children[number] = new TrieNode;
temp = temp->children[number];
}
在temp = temp->children[number];
块结束后应移动行if
,因为无论您是否创建新节点,都需要将temp
向前移动一步。
答案 1 :(得分:2)
在标准Trie中,Node结构中应该有另一个字段来指示它是否表示单词。
bool PrefixStringSet::contains(string s)
{
NodePtr temp = root;
for ( int i = 0; i < s.size(); i++)
{
if(temp->isWord)
{
return false;
}
if(temp->children[s[i] - '0'] == NULL)
{
return false;
}
temp = temp->children[s[i] - '0'];
}
return true;
}
bool PrefixStringSet::insert(string s)
{
if(contains(s) == true)
{
return false;
}
NodePtr temp = root;
for (int i = 0; i < s.size(); i++)
{
int number = (int)s[i] - (int)'0';
if(temp->children[number] == NULL)
{
temp->children[number] = new TrieNode;
}
temp = temp->children[number];
}
temp->isWord = true;
return true;
}
但是,在您的问题中,只有 LEAF 节点表示现有单词,因为您不允许任何数字成为此Trie中其他数字的前缀。
因此,您可以通过迭代其子节点来检查节点是否是叶子节点,如@timaru所说。但它效率不高。