• 【LeetCode】面试题19. 正则表达式匹配


    题目:

    思路:

    1、动态规划:从尾部开始(不从头部),清晰分析每种情况,划分子问题,得到转移方程,初始条件特殊单独分析处理

    • 定义状态dp[i][j]表示s的前i个字符和p的前j个字符是否匹配,注意前i个字符的下标是0~i-1
    • 重叠子问题,怎么确定dp[i][j]的状态?通过对比当前尾部的字符,将dp[i][j]的问题划分成子问题
      • s[i-1] == p[j-1]p[j-1] == '.':当前尾部两个字符完全匹配,则dp[i][j] = dp[i-1][j-1]
      • p[j-1]=='*':需要根据前一个字符确认
        • s[i-1] == p[j-2]p[j-2] == '.':则可以匹配0个或多个字符,匹配0个时dp[i][j] = dp[i][j-2],匹配多个时dp[i][j] = dp[i-1][j]
        • s[i-1] != p[j-2]*匹配0个字符,则dp[i][j] = dp[i][j-2]
      • 其它情况dp[i][j]=False
    • 转移方程
      ( DP_{i,j} = egin{cases} DP_{i-1,j-1} & s_{i-1}=p_{j-1} || p_{j-1}=. \ DP_{i-1,j} || DP_{i,j-2} & p_{j-1}=* , s_{i-1}=p_{j-2} || p_{j-2}=. \ DP_{i,j-2} & p_{j-1}=* , s_{i-1} e p_{j-2} \ False & others end{cases} )
    • 初始条件
      • 当两个字符串都为空时dp[0][0]=False
      • 当s不为空,p为空时dp[i][0]=False
      • 当s为空,p不为空时dp[0][j]的状态需要判断
    • 推导转移公式时是从后向前,得到公式之后计算时需要从前往后。因为后面的计算依赖前面已计算出来的结果

    2、既然能够分解成子问题就能够通过递归回溯求解,并且是从后向前进行,注意递归的结束条件

    代码:

    Python

    class Solution(object):
        def isMatch(self, s, p):
            """
            :type s: str
            :type p: str
            :rtype: bool
            """
            m = len(s)
            n = len(p)
            # 0表示空字符串, 1表示第一个字符, 第一个字符在字符串里下标是0
            dp = [[False for _ in range(n+1)] for _ in range(m+1)]
            dp[0][0] = True  # 都是空字符串
            for i in range(1, n+1):
                if p[i-1] == '*' and dp[0][i-2]:
                    dp[0][i] = True
            # 注意i,j在dp中和在s/p中的变化,容易乱
            for i in range(1, m+1):
                for j in range(1, n+1):
                    if s[i-1] == p[j-1] or p[j-1] == '.':
                        dp[i][j] = dp[i-1][j-1]
                    elif p[j-1] == '*':
                        if s[i-1] == p[j-2] or p[j-2] == '.':
                            dp[i][j] = dp[i-1][j] or dp[i][j-2]
                        else:
                            dp[i][j] = dp[i][j-2]
                    else:
                        dp[i][j] = False
            return dp[m][n]
    
    class Solution(object):
        def isMatch(self, s, p):
            """
            :type s: str
            :type p: str
            :rtype: bool
            """
            # 两个都为空
            if len(s) == 0 and len(p) == 0:
                return True
            # s不为空, p为空
            if len(p) == 0:
                return False
            # s为空, p不为空, 只要p的长度为偶数并且奇数位为*就能匹配
            if len(s) == 0:
                if len(p) % 2 != 0:
                    return False
                else:
                    for i in range(1, len(p), 2):
                        if p[i] != '*':
                            return False
                    return True
            # 两个都不为空, 进入递归
            if s[-1] == p[-1] or p[-1] == '.':
                return self.isMatch(s[:-1], p[:-1])
            elif p[-1] == '*':
                if s[-1] == p[-2] or p[-2] == '.':
                    return self.isMatch(s[:-1], p) or self.isMatch(s, p[:-2])
                else:
                    return self.isMatch(s, p[:-2])
            else:
                return False
    

    相关问题

  • 相关阅读:
    InSAR 大气校正数据 GACOS
    java通用的方法整理
    Jquery实现select左右栏的添加移除
    kendo ui之grid列表
    kendo-ui学习笔记(一)
    kendo-ui学习笔记——题记
    chrome driver驱动地址
    适合引入缓存的业务及影响
    个人测试方法论202108
    Redis缓存
  • 原文地址:https://www.cnblogs.com/cling-cling/p/12987731.html
Copyright © 2020-2023  润新知