原题地址:字模式node
给定一个模式串pattern和一个字符串str,请问str和pattern是否遵循相同的模式。 这里遵循模式指的是一个彻底匹配,即在pattern中的每一个不一样的字母和str中每一个非空的单词之间有一个双向映射的模式对应。bash
您能够认为模式串pattern只包含小写字母,而str包含由单个空间分隔的小写单词组成。ui
由于要一一对应的关系,因此要双向映射,因此须要两个map: 一个从pattern的字符到对应的单词,一个从单词到字符。spa
这里我没有使用系统的map,而是实现了一个 前缀树 来练练手,对于一个前缀树,一个节点能够和一个单词作一一对应的映射,对应的单词就是从跟沿着路径到这个节点的那个单词。因此能够在这个节点里存入跟单词对应的数据,就能够实现从单词到这个数据的映射,因此这里存入字符,实现从单词到pattern的字符的映射。code
从字符到单词的映射,有多个方案:ip
using namespace std;
namespace TFDataStruct {
template<class T>
class Trie{
public:
struct TrieNode{
char ch;
//对应的字符串的个数
uint32_t mark = 0;
T relateData; //作额外的数据处理
TrieNode *parent = nullptr;
unordered_map<char, TrieNode*> childern;
};
struct TrieNodeVisitor{
typedef void (*VisitFunc)(TrieNode *node, string &word, int idx);
VisitFunc visitF;
TrieNodeVisitor(VisitFunc visitF):visitF(visitF){};
};
private:
public:
TrieNode root;
Trie(){};
Trie(vector<string> &words){
for (auto &w : words){
insert(w, nullptr);
}
}
/** 插入一个元素,同时最后的节点 */
TrieNode *insert(string &word, TrieNodeVisitor visitor = nullptr){
TrieNode *node = &root;
int idx = 0;
while (idx<word.length()) {
auto &next = node->childern[word[idx]];
if (next == nullptr) {
next = new TrieNode();
next->ch = word[idx];
next->parent = node;
}
node = next;
if (visitor.visitF) visitor.visitF(node, word, idx);
idx++;
}
node->mark++;
return node;
}
int count(string &word){
TrieNode *node = &root;
int idx = 0;
while (idx<word.length()) {
auto &next = node->childern[word[idx]];
if (next == nullptr) {
return 0;
}
node = next;
idx++;
}
return node->mark;
}
bool exist(string &word){
return count(word)>0;
}
};
}
class Solution {
public:
/**
* @param pattern: a string, denote pattern string
* @param teststr: a string, denote matching string
* @return: an boolean, denote whether the pattern string and the matching string match or not
*/
bool wordPattern(string &pattern, string &teststr) {
teststr.push_back(' ');
//1. 前缀树记录的是单词到字符的对应关系,每一个节点惟一对应一个单词(即从跟到这个节点的路径拼起来的单词),因此用节点存储单词映射的字符;
//2. markC2W[c]表示c这个字符映射的单词,又由于节点和单词的一一对应关系,因此把单词对应的节点存入
TFDataStruct::Trie<char> trieW2C;
TFDataStruct::Trie<char>::TrieNode* charNodes[256];
memset(charNodes, 0, sizeof(charNodes));
//3. 由于要一一对应的关系,1和2恰好是两个方向
int start=-1, i = 0;
int wordIdx = 0;
for (auto &c : teststr){
if (start<0) {
if (c!=' ') {
start = i;
}
}else{
if (c==' ') {
auto str = teststr.substr(start, i-start);
auto node = trieW2C.insert(str);
auto charNode = charNodes[pattern[wordIdx]];
if (charNode == nullptr) {
if (node->relateData>0) {
return false;
}
}else if (node != charNode) {
return false;
}
node->relateData = pattern[wordIdx];
charNodes[pattern[wordIdx]] = node;
start = -1;
wordIdx++;
}
}
i++;
}
return true;
}
};
复制代码