[Leetcode] 10, 44, 69

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

Solution: 回溯法处理 '*' 号,而 '.' 作为万用字符直接处理。

Code:

class Solution {
public:
    bool isMatch(string s, string p) {
        return isMatch( 0, s, 0, p);
    }
private:
    bool isMatch(int sbegin, string& s, int pbegin, string& p){
        if(p[pbegin]=='\0'){
            if(s[sbegin]!='\0') return false;
            else return true;
        }
        
        //*不当作字符考虑,而是当作字符后缀
        if(p[pbegin+1]!='*'){
            if(p[pbegin]==s[sbegin] || (p[pbegin]=='.' && s[sbegin]!='\0'))
                return isMatch(sbegin+1, s, pbegin+1, p);
            else
                return false;
        }else{
            //backtracking,将*作为×0到×n代入测试是否能够得到一个合法解,n是直到无法代入p[pbegin]为止
            while(s[sbegin]==p[pbegin] ||  (p[pbegin]=='.' && s[sbegin]!='\0')){
                if(isMatch(sbegin, s, pbegin+2, p))
                    return true;
                else
                    sbegin++;
            }
            return isMatch(sbegin, s, pbegin+2, p);
        }
    }
};


44. Wildcard Matching

Implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

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", "*") ? true
isMatch("aa", "a*") ? true
isMatch("ab", "?*") ? true
isMatch("aab", "c*a*b") ? false

Solution:  递归会超时,使用循环进行回溯

原因在于即便使用了带记录的递归,对于p上的每一个'*',依然需要考虑'*' 匹配之后字符的所有情况,比如p = "c*ab*c",s = "cddabbac"时,遇到第一个'*',我们需要用递归处理p的剩余部分"ab*c" 和s的剩余部分"ddabbac"的所有尾部子集匹配。也就是:"ab*c"和"ddabbac","ab*c" 和"dabbac"的匹配,"ab*c" 和"abbac"的匹配,... ,"ab*c" 和"c"的匹配,"ab*c" 和"\0"的匹配。

遇到第二个'*',依然如此。每一个'*'都意味着p的剩余部分要和s的剩余部分的所有尾子集匹配一遍。

然而,我们如果仔细想想,实际上,当p中'*'的数量大于1个时,我们并不需要像上面一样匹配所有尾子集。

依然以 p = "c*ab*c",s = "cddabbac"为例。

对于p = "c*ab*c",我们可以猜想出它可以匹配的s应该长成这样: "c....ab.....c",省略号表示0到任意多的字符。我们发现主要就是p的中间那个"ab"比较麻烦,一定要s中的'ab'来匹配,因此只要s中间存在一个"ab",那么一切都可以交给后面的'*'了。

所以说,当我们挨个比较p和s上的字符时,当我们遇到p的第一个'*',我们实际只需要不断地在s的剩余部分找和'ab'匹配的部分。

换言之,我们可以记录下遇到*时p和s的位置,记为presp和press,然后挨个继续比较*(++p)和*(++s);如果发现*p != *s,就回溯回去,p = presp,s = press+1, ++press;直到比较到末尾,或者遇到了下一个'*',如果遇到了下一个'*',说明 "ab"部分搞定了,下面的就交给第二个'*'了;如果p和s都到末尾了,那么就返回true;如果到末尾了既没遇到新的'*',又还存在不匹配的值,press也已经到末尾了,那么就返回false了。

这样的思路和上面的递归比起来,最大的区别就在于:

遇到'*',我们只考虑遇到下一个'*'前的子问题,而不是考虑一直到末尾的子问题。从而避免大量的子问题计算。

Code: 

class Solution {
public:
    bool isMatch(string s, string p) {
        //两个*之间的部分,找到最早的匹配点即可
        //如果最早的匹配点依然不能保证匹配成功,那么一定不可能匹配成功
        int star = -2;
        int is=0, ip=0;
        while(s[is]){
            if(s[is] == p[ip] || p[ip] == '?'){
                is++;
                ip++;
            }else if(p[ip]=='*'){
                star= ip;
                ip++;
            }else{
                if(p[ip]=='\0' && (star == ip-1)) return true;
                //backtracking:回溯到前一个'*'
                if(star>=0){
                    is = is - (ip-star-2);
                    ip = star+1;
                }else{
                    return false;
                }
            }
        }
        while(p[ip]){
            if(p[ip]!='*') return false;
            ip++;
        }
        return true;
        
    }
};

69. Sqrt(x)

Implement int sqrt(int x).

Compute and return the square root of x.

Solution: 二分查找。

Code: 

class Solution {
public:
    int mySqrt(int x) {
        if(x<=1) return x;
        
        int i = 0;
        int j = x/2;
        while(i<=j){
            int middle = (i+j)/2;
            long k = pow(middle,2); //注意int越界问题
            if(k == x) return middle;
            else if(k > x) j = middle-1;
            else i = middle+1;
        }
        return j;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值