最長公共前綴和有效括號

其實最長公共前綴這個題目很容易就能想到水平掃描(兩兩比較,逐漸縮小範圍)或者垂直掃描(同時比較所有字符串的同一位),而且性能很好;稍微高級一點的想法大概是分治,但是分治佔用的空間有點大,畢竟是基於遞歸的。據說這種題目的通用解法是前綴樹,但是前綴樹我沒用過,所以記錄一下。

C++實現和Java實現還是有點區別的,尤其是在對null的判斷上。在Java裏可以很輕易地進行類似於object == null這樣的判斷,但是在C++裏就必須用指針。

// 結點
class TrieNode
{
private:
    TrieNode *next[26] = {nullptr};
    bool isEnd;
    // 非空子節點的數量
    int size = 0;

public:
    bool containsKey(char ch)
    {
        return next[ch - 'a'] != nullptr;
    }
    TrieNode *get(char ch)
    {
        return next[ch - 'a'];
    }
    void put(char ch, TrieNode *node)
    {
        next[ch - 'a'] = node;
        ++size;
    }
    void setEnd()
    {
        isEnd = true;
    }
    bool getEnd()
    {
        return isEnd;
    }
    int getLinks()
    {
        return size;
    }
};
// 樹
class Trie
{
private:
    TrieNode *root;

    // search a prefix or whole key in trie and
    // returns the node where search ends
    TrieNode *searchPrefix(string &word)
    {
        TrieNode *node = root;
        for (auto c : word)
        {
            if (node->containsKey(c))
            {
                node = node->get(c);
            }
            else
            {
                return nullptr;
            }
        }
        return node;
    }

public:
    /** Initialize your data structure here. */
    Trie()
    {
        root = new TrieNode();
    }

    /** Inserts a word into the trie. */
    void insert(string word)
    {
        TrieNode *node = root;
        for (auto c : word)
        {
            if (!node->containsKey(c))
            {
                node->put(c, new TrieNode());
            }
            node = node->get(c);
        }
        node->setEnd();
    }

    /** Returns if the word is in the trie. */
    bool search(string word)
    {
        TrieNode *node = searchPrefix(word);
        return node != nullptr && node->getEnd();
    }

    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix)
    {
        TrieNode *node = searchPrefix(prefix);
        return node != nullptr;
    }

    string searchLongestPrefix(const string &word)
    {
        TrieNode *node = root;
        string prefix;
        for (auto c : word)
        {
            if (node->containsKey(c) &&
                node->getLinks() == 1 &&
                !node->getEnd())
            {
                prefix += c;
                node = node->get(c);
            }
            else
            {
                return prefix;
            }
        }
        return prefix;
    }
};

至於有效括號,很顯然用輔助棧就可以解決。但是在選擇上有一些講究,在這種簡單的場景下,我們完全可以用數組自己實現一個棧,這樣可以減少空間的佔用。

感覺上,在簡單的情況下,數組比棧和map快,switch-case比map快;可能這就是減少對外部實體的依賴。

看到一句話,覺得很有道理:棧可以輔助我們進行從外向內的遞歸。這對於不清楚結構的問題是很有效的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章