力扣第十題題解 力扣第十題題解

力扣第十題題解

思路

問題描述就不寫了,直接放地址leecode

第一個問題

很簡單的想法就是使用雙指針,但是雙指針存在問題比如這個用例

aaa a*a

第一個a* 會盡可能多的匹配,然後就把aaa匹配完了。

正確的應該是a* 匹配兩個a,既然如此,就用遞歸,每一種情況都確保考慮到,匹配零個,匹配一個,匹配兩個...一直匹配到無法繼續找到能和當前pattern 匹配的字符。

第二個問題

存在a*.* 的特殊形式,這種時候但看a. 是沒有意義的,乾脆把a* 變成A.*變成:,因爲通過題目描述可知只有小寫字母,句號和星號。

如果題目改變,pattern 含有的信息增多,比如增加了?,就需要使用更多的變換方式,或者使用面向對象(當前不用考慮)。

第三個問題

有一步沒有添加字符串索引判斷,導致異常,力扣使用的是AddressSanitizer判斷的,但是錯誤頁面含有的信息很少,只好自己再電腦上測試,但是這個不支持Windows ,只好使用Linux子系統測試。

g++ -fsanitize=address -std=c++11 xxx.cpp -o xxx

顯示出了錯誤信息,但是沒有行數,像這樣

10_back+0x482c

這種的有點看不懂,將命令改爲

g++ -fsanitize=address -std=c++11 xxx.cpp -g -o xxx,添加了-g。還有一個參數,-fno-omit-frame-pointer,想要了解更多,可以看這個Optimize-Options(當前不用瞭解)。

xxx.cpp:47

代碼

增加了一個緩存,存儲已經匹配過的數據。

cache[i][j]代表的是pattern.substr(j) 是否能夠匹配str.substr(i)。

初始化爲u,如果能夠匹配改爲y,如果不能匹配,改爲爲n


class Solution {
public:
    vector<vector<char>> *cache = nullptr;

    bool isMatch(string str, string pattern) {
        vector<char> newPattern;
        delete cache;
        cache = new vector<vector<char>>();
        for (int i = 0; i < pattern.length(); i++) {
            char current = pattern[i];
            char c = current;
            if (i < pattern.length() - 1) {
                char next = pattern[i + 1];
                if (next == '*') {
                    if (current == '.') {
                        c = ':';
                    } else {
                        c = (char) (current - 32);
                    }
                    i++;
                }
            }
            newPattern.push_back(c);
        }

        for (int i = 0; i < str.length(); i++) {
            vector<char> v;
            v.reserve(newPattern.size());
            for (int j = 0; j < newPattern.size(); ++j) {
                v.push_back('u');
            }
            cache->push_back(v);
        }
        bool result = toNextMatch(str, newPattern, 0, 0);
        return result;
    }

    bool toNextMatch(string &str, vector<char> &pattern, int str_pointer, int pat_pointer) {
        if (str_pointer < str.length() && pat_pointer < pattern.size())
            if (cache->at(str_pointer)[pat_pointer] != 'u') {
                //cout<<str.substr(str_pointer,str.length()-1)<<" "<<pat_pointer<<" 直接返回結果"<<endl;
                return cache->at(str_pointer)[pat_pointer] == 'y';
            }

        //cout<<"toNextMatch method called "<<str.length()<<" "<<str_pointer<<" "<<pattern.size()<<" "<<pat_pointer<<endl;
        if (pat_pointer == pattern.size()) {
            return str_pointer == str.length(); //檢查pattern 是否消耗完了,如果沒有消耗完,代表不匹配
        }
        char pattern_current = pattern[pat_pointer];
        if (pattern_current == ':' || isBigger(pattern_current)) {
            //複雜字符,可能匹配多個,也可能一個不匹配
            bool zero_match = toNextMatch(str, pattern, str_pointer, pat_pointer + 1); //一個也沒有匹配
            if (str_pointer < str.length() && pat_pointer + 1 < pattern.size())
                cache->at(str_pointer)[pat_pointer + 1] = (zero_match ? 'y' : 'n');
            if (zero_match) {
                return true; //我一個也不匹配,後面的pattern 告訴我成功了,那我還能什麼,直接返回成功
            }                //如果失敗了,也不要氣餒,繼續匹配


            int start = str_pointer;
            while (start < str.length()) {
                //cout<<"offset "<<(start-str_pointer+1)<<endl;
                if (match(str[start], pattern_current)) { //匹配成功,並且打算就匹配到這個位置,後面的數據,嘗試讓後面的pattern 去匹配
                    int offset = str_pointer + start - str_pointer + 1;
                    bool unknown = toNextMatch(str, pattern, offset, pat_pointer + 1);
                    if (offset < str.length() && pat_pointer + 1 < pattern.size())

                        cache->at(offset)[pat_pointer + 1] = unknown ? 'y' : 'n';
                    if (unknown) {
                        //cout<<"return true"<<endl;
                        return true;
                    } //雖然失敗了,也不要氣餒,後面還有機會,堅持就是勝利
                } else {
                    //儘可能地匹配都沒有一個可以成功的,最終也會失敗,等着從while 出去再返回false,因爲存在str匹配完了的問題
                    break;
                }
                start++;
            }
            return false; //毀滅吧,我累了
        } else {
            if (str_pointer >= str.length()) {
                return false;
            }

            //普通字符,匹配一個,就結束
            if (match(str[str_pointer], pattern_current)) {
                //cout<<"next"<<endl;
                return toNextMatch(str, pattern, str_pointer + 1, pat_pointer + 1); //匹配成功,繼續向下匹配
            } else {
                return false; //匹配失敗,不需要繼續進行下去了
            }
        }
    }

    static bool isBigger(char c) {
        return c >= 'A' && c <= 'Z';
    }

    static bool match(char _s, char _p) {
        //cout<<"match called "<<_s<<"-"<<_p<<endl;
        if (isBigger(_p)) {
            return _s - _p == 32;
        } else if (_p == ':') {
            return true;
        } else if (_p == '.') {
            return true;
        } else {
            return _s == _p;
        }
    }
    ~Solution(){
        delete cache;//析構函數,否則會內存泄漏,AddressSanitizer挺好用
    }
};

其他的解題思路

動態規劃,有限狀態機

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