LeetCode(10)RegularExpresssionMatching

我觉这道题目得挺难的,想了很久也没想清楚%>_<%于是看了解题报告

题目解释

'.' 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

给定的例子中,有一个比较难懂,是这样的。
isMatch("ab", ".*") → true
这个式子的判定结果是true。理由是.*理解为重复任意字符任意次.......而a是任意字符,b也是任意字符。所以ture


基本思路:
比较困难的问题在这里。看下面两个例子的比较:
例1: isMatch("aaaaab","a*b"),
为了表达方便记录为    isMatch("a1a2a3a4a5b1","a6*b2"),
显然a6应该匹配a1a2a3a4a5,然后b2匹配b1。

例2: isMatch("aaaaab","a*ab"),
为了表达方便记录为    isMatch("a1a2a3a4a5b1","a6*a7b2"),
显然a6应该匹配a1a2a3a4,然后a7匹配a5,然后b2匹配b1。
于是发现,当正则表达式中有*的时候,比较讨厌,你不知道到底要在s中匹配多长。
这个问题的结构说明这个问题天生适合用递归来解决。就像leetcode的解答报告中说的If you are stuck, recursion is your friend.
这个问题的结构还说明*很特殊所以需要特殊对待,于是基本思路是
把p分隔为若干个小单位,要么是一个字符构成的小单位,要么是一个字符和后面一个'*'构成的小单位。
逐一检查这样的小单位是否能够和s匹配。这其中,到底这样的小单位匹配多长的s是需要我们逐一检查的,也就是需要我们暴力一下的。

抄袭代码:

//
//  Solution.h
//  LeetCodeOJ_010_RegMatching
//
//  Created by feliciafay on 12/4/13.
//  Copyright (c) 2013 feliciafay. All rights reserved.
//

#ifndef LeetCodeOJ_010_RegMatching_Solution_h
#define LeetCodeOJ_010_RegMatching_Solution_h
#include <iostream>
#include <string>
#include <assert.h>
// Input:	"bbbba", ".*a*a"
class Solution {
public:
    bool isMatch(const char *s, const char *p) {
        assert(s && p);
        if (*p == '\0') return *s == '\0';
        
        // next char is not '*': must match current character
        if (*(p+1) != '*') {
            assert(*p != '*');
            return ((*p == *s) || (*p == '.' && *s != '\0')) && isMatch(s+1, p+1);
        }
        // next char is '*'
        while ((*p == *s) || (*p == '.' && *s != '\0')) {
            if (isMatch(s, p+2))
                return true;
            s++;
        }
        //继续匹配剩下的部分
        return isMatch(s, p+2);
        }
};
#endif

小结
(1)欣赏一下这句的简洁和巧妙 
return ((*p == *s) || (*p == '.' && *s != '\0')) && isMatch(s+1, p+1);
(2)
注意这里是
    if (isMatch(s, p+2)) return true;
而不是
    return  (isMatch(s, p+2));
因为逻辑是,在若干次暴力搜索中,只要又一次匹配就返回true,不管之前失败了几次。
(3)
之前个人错误地认为逻辑其实应该是
//错误写法
s++;
if (isMatch(s, p+2)) return true;
但是实际正确写法却是

if (isMatch(s, p+2)) return true;
s++;
为什么呢?

看这样一个例子就能理解了。 isMatch(“a”, "a*a"),这里"a"和"a*a"显然应该是匹配的。为了方便,表达为
原串: a1
正则: a2*a3
如果按照错误写法,那么a1匹配a2之后,将检查a3和'\0'发现不匹配于是返回结果为不匹配。
可是实际上,a2*表达的意思是把a2重复0次或者多次,错误的写法没有考虑到把a2重复0次的情况。
按照正确的写法,就可以考虑到a2重复0次的情况,从而判断a1是否匹配a3,从将最终结果返回为匹配。
所以正确的写法是

if (isMatch(s, p+2)) return true;
s++;
(4) LeetCode对思路讲解的的 原话

We need some kind of backtracking mechanism such that when a matching fails, we return to the last successful matching state and attempt to match more characters in s with ‘*’. This approach leads naturally to recursion.

If the next character of p is NOT ‘*’, then it must match the current character of s. Continue pattern matching with the next character of both s and p.
If the next character of p is ‘*’, then we do a brute force exhaustive matching of 0, 1, or more repeats of current character of p… Until we could not match any more characters.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值