zoukankan      html  css  js  c++  java
  • LeetCode10 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   (hard)



    分析:
    题目意思是 正则表达式匹配,'.'匹配任意字符, '*'表示前一个字符可以出现任意多次(0次,1次,2次...)
    如ab 与 .* :将.出现两次为..可以匹配任意字符,所有可以匹配ab
    aab 与 c*a*b :c*将c出现0次, a*将a出现两次,得到aab可以匹配。

    而且特殊符号是只出现在p字符串中的(开始没理解这个导致感觉问题很复杂推不下去...,可能因为没学过正则表达式)

    解析:
    采用动态规划。双序列动态规划常见得状态选取即为dp[i][j]表示s的前i个与p的前j个...
    对应于本题,dp[i][j]表示s的前i个字符与p的前j个字符能否匹配。 但本题递推关系不是很好推完整(毕竟hard)
    当p[j-1] != '*'
        需要s[i-1] == p[j-1] 并且 dp[i-1][j-1] == true (前i-1个与前j-1个能匹配)
    当p[j-1] == '*'
        有如下几种情况:
        1)*前的字符需要重复0次 例如匹配 ab 和 aba*, 该情况下dp[i][j]是否为真取决于 dp[i][j-2] 是否为真;
        2)*前的字符需要重复1次,即其本身,如匹配 aba 和 aba*, 该情况下dp[i][j]是否为真取决于dp[i][j-1]是否为真;
        3)*前字符需要重复2次或以上, 如匹配 abaa 与 aba*(出现两次), 匹配aaa与.*(出现大于两次);
          该情况下需要s[i-1] == p[j-2] && (dp[i-1][j-1] || dp[i-1][j]) // dp[i-1][j]容易忽略,表示要利用*前元素大于两次;

    初始化dp[0][0], dp[i][0] (i = 1,2,...s.size()) , dp[0][j], (j = 1,2,...p.size());
    其中dp[0][j]的需要点判断, p[j - 1] == '*' &&  dp[0][j - 2] (即*帮助去掉了前面的字符。开始还写了||dp[0][j-1],后来发现*不会打头存在,所以dp[0][j-1]没必要)

    代码:(还有一些小细节在注释中)
     1 class Solution {
     2 public:
     3     bool isMatch(string s, string p) {
     4         bool dp[s.size() + 1][p.size() + 1];
     5         dp[0][0] = true;
     6         for (int i = 1; i <= s.size(); ++i) {
     7             dp[i][0] = false;
     8         }
     9         for (int j = 1; j <= p.size(); ++j) {
    10              //p[j-2]一定存在,*不会打头!
    11              if (p[j - 1] == '*' &&  dp[0][j - 2])  {
    12                 dp[0][j] = true;
    13             }
    14             else {
    15                 dp[0][j] = false;
    16             }
    17         }
    18     
    19         for (int i = 1; i <= s.size(); ++i) {
    20             for (int j = 1; j <= p.size(); ++j) {
    21                 if (p[j - 1] != '*') {
    22                     dp[i][j] =  (s[i - 1] == p[j - 1] || p[j - 1] == '.') && dp[i - 1][j - 1];
    23                 }
    24                 else {
    25                     //重复两次或更多   dp[i-1][j]  如:aaa与.*
    26                     // * 不会打头,所以p[j - 2]一定存在
    27                     bool b1 = (s[i - 1] == p[j - 2] || p[j - 2] == '.') && (dp[i - 1][j - 1] || dp[i - 1][j]);
    28                     bool b2 =  dp[i][j - 1];  //重复1次
    29                     bool b3 =  dp[i][j - 2];  //重复0次
    30                     dp[i][j] = b1 || b2 || b3;
    31                 }
    32             }
    33         }
    34         return dp[s.size()][p.size()];
    35     }
    36 };
    学习了一下讨论区,发现递推的情况基本是一样的,有一点细微的优化。

    我做的时候是先想到类似abaa 与 aba*, *前字符重复两次,所以写出了dp[i - 1][j - 1]。(标红前半句)
    提交之后WA发现有情况没考虑到,即aaa与.* 即出现大于两次,所以添加了dp[i-1][j]
    而现在仔细考虑,实际上只需要一句dp[i-1][j]就可以处理大于等于2次重复的情况,所以标红句可以优化为
    bool b1 = (s[i - 1] == p[j - 2] || p[j - 2] == '.') &&  dp[i - 1][j];
    
    
    
     
    
    




  • 相关阅读:
    C#中关于值类型和引用类型的区别
    Win32_PhysicalMedia 硬盘 参数说明
    Win32_DiskDrive 硬盘 参数说明
    Win32_Processor CPU 参数说明
    通过EF操作Sqlite时遇到的问题及解决方法
    在VS2017中连接到SQLite数据源(dbfist)
    Sqlite 的管理工具SQLite
    Navicat for mysql 免费破解工具+教程
    基于C#的机器学习--模糊逻辑-穿越障碍
    基于C#的机器学习--惩罚与奖励-强化学习
  • 原文地址:https://www.cnblogs.com/wangxiaobao/p/5758986.html
Copyright © 2011-2022 走看看