前綴樹小試:字模式

原題地址:字模式

給定一個(gè)模式串pattern和一個(gè)字符串str,請(qǐng)問str和pattern是否遵循相同的模式。
這里遵循模式指的是一個(gè)完全匹配,即在pattern中的每個(gè)不同的字母和str中每個(gè)非空的單詞之間有一個(gè)雙向映射的模式對(duì)應(yīng)。

您可以認(rèn)為模式串pattern只包含小寫字母,而str包含由單個(gè)空間分隔的小寫單詞組成。

因?yàn)橐灰粚?duì)應(yīng)的關(guān)系,所以要雙向映射,所以需要兩個(gè)map: 一個(gè)從pattern的字符到對(duì)應(yīng)的單詞,一個(gè)從單詞到字符。

這里我沒有使用系統(tǒng)的map,而是實(shí)現(xiàn)了一個(gè) 前綴樹 來練練手,對(duì)于一個(gè)前綴樹,一個(gè)節(jié)點(diǎn)可以和一個(gè)單詞做一一對(duì)應(yīng)的映射,對(duì)應(yīng)的單詞就是從跟沿著路徑到這個(gè)節(jié)點(diǎn)的那個(gè)單詞。所以可以在這個(gè)節(jié)點(diǎn)里存入跟單詞對(duì)應(yīng)的數(shù)據(jù),就可以實(shí)現(xiàn)從單詞到這個(gè)數(shù)據(jù)的映射,所以這里存入字符,實(shí)現(xiàn)從單詞到pattern的字符的映射。

從字符到單詞的映射,有多個(gè)方案:

  1. unordered_map<char, string>,用char做key, word做value
  2. 因?yàn)槎际切懽帜?,所以可以?string[26]來標(biāo)記,string[c-'a']就可以得到字符c的word,比較
  3. 因?yàn)榍熬Y樹里節(jié)點(diǎn)跟單詞一一對(duì)應(yīng),所以可以直接存入節(jié)點(diǎn),結(jié)合2的思路就是:TrieNode[26]. 相比2的好處是,比較單詞相等不用string.compare了,直接比較兩個(gè)節(jié)點(diǎn)是否相等就可以了。前綴樹是節(jié)點(diǎn)不會(huì)刪除,讓這一點(diǎn)成為了可能。這樣做復(fù)雜度直接從O(N*L)到了O(N),L是字符串的平均長(zhǎng)度。

using namespace std;

namespace TFDataStruct {
    template<class T>
    class Trie{
    public:
        struct TrieNode{
            char ch;
            //對(duì)應(yīng)的字符串的個(gè)數(shù)
            uint32_t mark = 0;
            T relateData;  //做額外的數(shù)據(jù)處理
            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);
            }
        }
        
        /** 插入一個(gè)元素,同時(shí)最后的節(jié)點(diǎn) */
        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. 前綴樹記錄的是單詞到字符的對(duì)應(yīng)關(guān)系,每個(gè)節(jié)點(diǎn)唯一對(duì)應(yīng)一個(gè)單詞(即從跟到這個(gè)節(jié)點(diǎn)的路徑拼起來的單詞),所以用節(jié)點(diǎn)存儲(chǔ)單詞映射的字符;
    //2. markC2W[c]表示c這個(gè)字符映射的單詞,又因?yàn)楣?jié)點(diǎn)和單詞的一一對(duì)應(yīng)關(guān)系,所以把單詞對(duì)應(yīng)的節(jié)點(diǎn)存入
    TFDataStruct::Trie<char> trieW2C;
    TFDataStruct::Trie<char>::TrieNode* charNodes[256];
    memset(charNodes, 0, sizeof(charNodes));
    
    //3. 因?yàn)橐灰粚?duì)應(yīng)的關(guān)系,1和2剛好是兩個(gè)方向
    
    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;
}
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 最先接觸編程的知識(shí)是在大學(xué)里面,大學(xué)里面學(xué)了一些基礎(chǔ)的知識(shí),c語(yǔ)言,java語(yǔ)言,單片機(jī)的匯編語(yǔ)言等;大學(xué)畢...
    oceanfive閱讀 3,395評(píng)論 0 7
  • 一、正則表達(dá)式的用途(搜索和替換) 1.1.正則表達(dá)式(regular expression,簡(jiǎn)稱regex)是一...
    IIronMan閱讀 10,273評(píng)論 0 14
  • python的re模塊--細(xì)說正則表達(dá)式 可能是東半球最詳細(xì)最全面的re教程,翻譯自官方文檔,因?yàn)楣俜轿臋n寫的是真...
    立而人閱讀 23,449評(píng)論 4 46
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,717評(píng)論 0 5
  • 小時(shí)候放假是為了盼著回家看電視,再后來是為了和朋友出去旅行,而如今我卻格外的想家。 五一假期,本來不打算回家。因?yàn)?..
    52b22a640e0e閱讀 367評(píng)論 0 0

友情鏈接更多精彩內(nèi)容