LeetCode:正则表达式匹配

补上周缺失的LeetCode;

题目:

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

来源:力扣(LeetCode)

解题思路:

way一:回溯法

用Pattern和s进行匹配时,Pattern有几种情况:
cond1:pattern中没“*”号,则pattern[i] in {text[i],“.”},则说明匹配;
cond2:pattern中有“*”号:
在cond2中,pattern和s的模式匹配形式有如下几种:
first = pattern[i] in {text[i],“.”} and i<len(text)
if i+1 <= len(pattern)-1 and pattern[i+1] == “*”:
return isMatch(s[i],pattern[i+2]) or (first and isMatch(s[i+1],pattern[i])
else:
return isMatch(s[i+1],pattern[i+1])

上述的几种情况,有以下几种递归形式:dp(i,j) :
dp(i+1,j) #1
dp(i,j+2) #2
dp(i+1,j+1) #3
可以看出,如果我们现在想去dp(i+2,j+2),则可通过以下几种路径来实现:
dp(i,j) -> #3 -> #3 -> dp(i+2,j+2)
dp(i,j) -> #1 -> #1 -> #2 -> dp(i+2,j+2)
由此可知,在上述递归算法中,存在着 无数条 重叠子问题,因此,我们可以用 “动态规划”的方法对其进行优化。
这里 所谓“动态规划”,其实就是在“递归”的基础上,加了一个“备忘录”,来记住 各个子问题的 value;
先给出 “递归算法” 的code,在 “way二”中,给出“动态规划”的code;

//Java
class Solution{
    public boolean isMatch(String s,String p){
        if(pattern.isEmpty()):return s.isEmpty();
        first = (!s.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == "."));
        if(p.length()>=2 && p.charAt(1)=="*"){
            return isMatch(s.substring(0),p.substring(2)) || (first && isMatch(s.substring(1),p))
        else:
            return (first && isMatch(s.substring(1),p.substring(1)))
   }
}    
way二:动态规划法

动态规划法 是在 递归算法的基础上,加了一个备忘录,记录已经处理过的子问题,从而 防止程序进行重复计算。其code如下:

//java
class Solution{
    public boolean isMatch(String s,String p){
        boolean[][] dp = new boolean[s.length()+1][p.length()+1];  //这里之所以用 p.length+1,是为了防止 p.substring(j+2)时溢出;   
        return dp(0,0,s,p);
    }
    public boolean dp(int i,int j,String s,String p){
        boolean ans;
        if(dp[i][j] != null){
            return dp[i][j];
        } //使用备忘录中记录的值,避免 子问题的重复计算;
        if(j == p.length()){
            ans = i == s.length();
        } // i,j都超出了 数组index,这种情况发生在P中有 星号 的时候
        else{
            first = (i < s.length() && (p.charAt(j) == s.charAt(i) || p.charAt(j) == "."));
            if(j<= p.length()-2 && p.charAt(j+1) == "*"){
                ans = (dp(i,j+2,s,p) || (first && dp(i+1,j,s,p)));
            } //要么 *代表0次,要么*代表1次
            else{
               ans = (first && dp(i+1,j+1,s,p));
            }
        }
        dp[i][j] = ans;
        return ans;
    }
}   

总结:
我觉得最赞的一点是,巧妙的利用dp(i+1,j,s,p)的方式来实现 * 的无限循环;


看过一部电影,听过一句话:
“这世上坏人之所以猖獗,是因为好人的无所作为” ;
喜欢 唐晶,胸怀正念,也能比贱斗恨;

今天推荐一首歌《听风无涯》:

是谁信笔描绘水墨江山
苍青色依旧深沉如海
往事终于缭乱成繁华斑斓
望不穿他眼中流年荏苒
轻声在梦中
唤无涯成沧海
像枫色飘零
转眼情波成潭
渐渐消失渐渐消失
将回忆点燃
留下残骸不在看

在也回不去的年少时光
在也不想见的人
后悔遇见

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Sarah ฅʕ•̫͡•ʔฅ

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值