[LeetCode] 10. Regular Expression Matching

思路1:
递归肯定会比较慢, 就直接上动态规划了. 要多建立一行和一列, 因为要考虑空字符串的情况.
flags[i][j]表示子串s[0…i - 1]是否匹配p[0…j - 1].
flags[0][0]一定是真, 因为空字符串一定能匹配空字符串.
除了第0项, 剩下的第0列一定都是假, 因为如果p是空字符串, 那么他就只能匹配空字符串而已.
除了第0项, 剩下的第0行要遵循以下三个条件才能是真:
1) 下标要大于1, 意思是子串必须长度大于等于2;
2) 当前字符必须是’*’;
3) 向前数2个, flags[0][j -2], 意思就是”x*”不重复的时候也要能匹配才可以
初始化工作算是结束了, 下面开始填满剩余的矩阵.
flags[i][j]为真要满足以下条件二选一:
1) 当当前字符为”*”时:
“x*”不重复的时候, 也就是flags[i][j - 2]的值为真;
“x*”至少重复一次的时候, 包括p的上一个字符和s的当前字符相同, 或者p的上一个字符为’.’;
和在重复的情况下, s的上一个子串也匹配
2) 当当前字符不为”*”时:
要看s的上一个子串和p的上一个子串是否匹配;
以及s当前字符和p的当前字符是否相等, 或者p当前字符是不是’.’.

bool isMatch(string s, string p) {
    int slen = s.length(), plen = p.length();
    bool flags[slen + 1][plen + 1];
    flags[0][0] = true;

    for (int j = 1; j <= plen; j++)
        flags[0][j] = j > 1 && p[j - 1] == '*' && flags[0][j - 2];
    for (int i = 1; i <= slen; i++)
        flags[i][0] = false;
    for (int i = 1; i <= slen; i++) {
        for (int j = 1; j <= plen; j++) {
            if (p[j - 1] == '*')
                flags[i][j] = flags[i][j - 2] 
                    || (p[j - 2] == s[i - 1] || p[j - 2] == '.') 
                        && flags[i - 1][j];
            else
                flags[i][j] = flags[i - 1][j - 1] && 
                            (p[i - 1] == s[i - 1] || p[i - 1] == '.');
        }
    }
    return flags[slen][plen];
}

第二个版本:
思路依然是动态规划, 但是因为每次我们最多只需要上一次的结果, 所以可以把O(m * n)的空间开销节省为O(n)的, 只开两个数组循环交替存取数据就好, 而不用开辟整个m * n的矩阵空间.

bool isMatch(string s, string p) {
    int slen = s.length(), plen = p.length();
    int prev = 0, cur = 0;
    bool flags[2][plen + 1];
    flags[0][0] = true;

    for (int j = 1; j <= plen; j++)
        flags[0][j] = j > 1 && p[j - 1] == '*' && flags[0][j - 2];

    cur = 1 - cur;
    for (int i = 1; i <= slen; i++) {
        flags[cur][0] = false;
        for (int j = 1; j <= plen; j++) {
            if (p[j - 1] == '*')
                flags[cur][j] = flags[cur][j - 2]
                                || (p[j - 2] == s[i - 1] || p[j - 2] == '.')
                                    && flags[prev][j];
            else 
                flags[cur][j] = flags[prev][j - 1]
                                && (p[j - 1] == s[i - 1] || p[j - 1] == '.');
        }
        swap(cur, prev);
    }

    return flags[prev][plen];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值