LeetCode 10 - Regular Expression Matching

Regular Expression Matching

Implement regular expression matching with support for '.' and '*'.

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true

DP Code

class Solution
{
public:
    /* dp[i][j]:
     * true  -> s[0...i-1] matches p[0...j-1]
     * flase -> otherwise
     *
     * (1) trivial string
     * p[i][j] = p[i-1][j-1], if p[j-1] != '*' && (s[i-1] == p[j-1] || p[j-1] == '.')
     * (2) x* matches empty string
     * p[i][j] = p[i][j-2], if p[j-1] == '*'
     * (3) x* -> xx*, i.e. x repeats for at least 1 times
     * p[i][j] = p[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.'), if p[j-1] == '*'
     */
    bool isMatch(string s, string p)
    {
        int m = s.length(), n = p.length();

        vector<vector<bool> > dp(m+1, vector<bool>(n+1, false));
        dp[0][0] = true; // initialization

        for (int i = 0; i <= m; i++)
            for (int j = 1; j <= n; j++)
                if (p[j-1] == '*')
                    dp[i][j] = dp[i][j-2] || i > 0 && dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.');
                else
                    dp[i][j] = i > 0 && dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.');

        return dp[m][n];
    }
};
Runtime:  20 ms

Backtrack Code

struct backtrackPoint
{
    int stringIndex, patternIndex;

    backtrackPoint() { stringIndex = patternIndex = 0; }
    backtrackPoint(int stringIndex, int patternIndex): stringIndex(stringIndex), patternIndex(patternIndex){ }
};

struct pattern
{
    string s;
    pattern(const string& s): s(s) { c = '\0'; }

    char c;
    pattern(char c): c(c) { s = ""; }

    pattern() { c = '\0'; s = ""; }
};

class Solution
{
public:
    bool isMatch(string s, string p)
    {
        // get patterns
        vector<pattern> patterns;
        int start = 0, end = 0;
        for (int i = 0; i < p.length(); i++)
        {
            if (p[i] == '.')
            {
                end = i - 1;

                if (end >= start)
                    patterns.push_back(pattern(p.substr(start, end - start + 1)));

                if (i+1 < p.length() && p[i+1] == '*')
                {
                    patterns.push_back(pattern('.'));

                    i++;
                }
                else
                    patterns.push_back(pattern("."));

                start = i + 1;
            }
            else if (p[i] == '*')
            {
                end = i - 2;

                if (end >= start)
                    patterns.push_back(pattern(p.substr(start, end - start + 1)));

                patterns.push_back(pattern(p[i-1]));

                start = i + 1;
            }
        }
        if (p[p.length() - 1] != '*')
            patterns.push_back(pattern(p.substr(start)));

        // print patterns
        /*
        for (int i = 0; i < patterns.size(); i++)
        {
            cout << "Patterns[" << i << "]: ";
            if (patterns[i].s.length() > 0)
                cout << patterns[i].s << " ";
            else
                cout << patterns[i].c << "* ";
            cout << endl;
        }
        */

        int patternIndex = 0;
        int m = 0;
        stack<backtrackPoint> backtrackPoints;
        bool backtrack = false;
        while (true)
        {
            //cout << "stringIndex: " << m << " patternIndex: " << patternIndex << " backtrackPoints.size(): " << backtrackPoints.size() << endl;

            if (patternIndex == patterns.size()) // pass all sub pattern(s), check
            {
                if (m == s.length())
                    return true;
                if (m < s.length()) // the whole string matches preceding sub pattern(s) of the whole pattern, backtrack
                {
                    if (backtrackPoints.size() > 0)
                    {
                        backtrackPoint point = backtrackPoints.top();
                        backtrackPoints.pop();
                        m = point.stringIndex;
                        patternIndex = point.patternIndex;
                        backtrack = true;
                        continue;
                    }
                    else
                        return false;
                }
            }

            pattern currentPattern = patterns[patternIndex];

            if (m == s.length())
            {
                bool flag = true;
                for (int idx = patternIndex; idx < patterns.size(); idx++)
                    if (patterns[idx].s.length() > 0)
                    {
                        flag = false;
                        break;
                    }
                if (flag) // current and latter sub pattern(s) are all star expression(s)
                    return true;
                else // backtrack
                {
                    if (backtrackPoints.size() > 0)
                    {
                        backtrackPoint point = backtrackPoints.top();
                        backtrackPoints.pop();
                        m = point.stringIndex;
                        patternIndex = point.patternIndex;
                        backtrack = true;
                        continue;
                    }
                    else
                        return false;
                }
            }

            if (currentPattern.s.length() > 0) // trivial string
            {
                if (currentPattern.s.compare(".") == 0 || s.compare(m, currentPattern.s.length(), currentPattern.s) == 0)
                {
                    m += currentPattern.s.length();
                    patternIndex++;
                }
                else // backtrack
                {
                    if (backtrackPoints.size() > 0)
                    {
                        backtrackPoint point = backtrackPoints.top();
                        backtrackPoints.pop();
                        m = point.stringIndex;
                        patternIndex = point.patternIndex;
                        backtrack = true;
                        continue;
                    }
                    else
                        return false;
                }
            }
            else // star expression
            {
                if (backtrack == true) // eat a character
                {
                    backtrack = false;
                    if (currentPattern.c == '.' || s[m] == currentPattern.c) // eat a character
                    {
                        m++;
                        backtrackPoints.push(backtrackPoint(m, patternIndex));
                        patternIndex++;
                    }
                    else // backtrack
                    {
                        if (backtrackPoints.size() > 0)
                        {
                            backtrackPoint point = backtrackPoints.top();
                            backtrackPoints.pop();
                            m = point.stringIndex;
                            patternIndex = point.patternIndex;
                            backtrack = true;
                            continue;
                        }
                        else
                            return false;
                    }
                }
                else // eat no character, i.e. pass current star expression
                {
                    backtrackPoints.push(backtrackPoint(m, patternIndex));
                    patternIndex++;
                }
            }
        }
        cout << "Error: undefined!" << endl;
    }
};
Runtime:  368 ms

Recursive Code

class Solution
{
public:
    bool isMatch(string s, string p)
    {
        if (p.empty())
            return s.empty();

        if (p[1] == '*')
            // x* matches empty string or at least one character: x* -> xx*
            return isMatch(s, p.substr(2)) ||
                    !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p);
        else
            // trivial string
            return !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p.substr(1));
    }
};
Runtime:  624 ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EnjoyCodingAndGame

愿我的知识,成为您的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值