zoukankan      html  css  js  c++  java
  • lintcode154

    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(string s, string p)
    Example
    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

    DP。 O(m*n), m为string长度,n为pattern长度
    1.定义:dp[i][j]是s.substring(0, i)和p.substring(0, j)是否为匹配对,从头开始对比。
    2.状态转移方程:
    a)dp[i][j] = dp[i - 1][j - 1]; 在两个字符相等或p的字符为’.’时。(从左上来)
    b)dp[i][j] = dp[i][j - 2] || (dp[i - 1][j] && (p[j - 1] == s[i] || p[j - 1] == ‘.')); 在p的字符为’*’时,而且其中一种情况需要*前面的那个字符得是’.’或者和s当前字符相同。(从上一格来和从左两格来)
    c)dp[i][j] = false; 其他情况,其实也就是两个字符不相同而且p的不是特殊字符时。
    3.初始化:dp[0][0]=true, 第一行也就是声明空s”"是否匹配一段段pattern的时候,如果遇到p.c ==‘*’的情况,要取左边两格的值(让a*或者.*什么的此时表示为空,从而保证”"能匹配上a*,a*b*,a*b*.*这些pattern)。第一列也就是声明空p是否匹配一段段的string,肯定都是false啊。
    4.刷新方向,自上而下,从左到右。
    5.具体解释:
    2a)在字符串相等或者’?’被迫匹配到s的当前字符的时候,当前位置合格了,你得把这两个字符擦掉看前面的合格不合格。
    2b)dp[i][j - 2]就是说把a*这种看成空的,如果看空了是true的那肯定能借鉴过来。
    dp[i - 1][j]就是把a*这种看成1个或多个a,这样你就要把s里那个匹配上的a给吞掉,但是j不改变让a*保留,因为后续对比a*说不定还可以发挥用途继续吞,有没有进一步代表那是dp[i-1][j]帮你去判断的事。值得注意的是这时候能吞的情况必须要*前的那个字母符合吞吞条件呀,所以一定要和当前s[i]相同或者是万能吞吞符’.’。
    2c)普通字符当前位置都匹配不上那就不可能了,你整个字符串宏观看,最后一个是普通字符而且不一样的话,前面的*?再怎么巧妙也解决不了最后不同的问题啊。

    细节:
    1.题意:a*这种是可以表示0,1,n个a。.*这种事可以表示0,1,n个.,所以可以变形成不同的字母如.*==ab。
    2.数组大小是[s.length()+1][p.length()+1],留出上左的行列给初始化的。所以给数组赋值的下标和取substring的下标有一个offset,要小心。所以正式part循环是[1, length()],取char是substring(i - 1)。

    参考视频:https://www.youtube.com/watch?v=l3hda49XcDE&t=194s

    实现:

    public class Solution {
        /**
         * @param s: A string 
         * @param p: A string includes "." and "*"
         * @return: A boolean
         */
        public boolean isMatch(String s, String p) {
            // write your code here
            
            boolean[][] isMatch = new boolean[s.length() + 1][p.length() + 1];
            isMatch[0][0] = true;
            
            for (int j = 1; j <= p.length(); j++) {
                if (p.charAt(j - 1) == '*' && j >= 2) {
                    isMatch[0][j] = isMatch[0][j - 2];
                }
            }
            
            for (int i = 1; i <= s.length(); i++) {
                for (int j = 1; j <= p.length(); j++) {
                    if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {
                        isMatch[i][j] = isMatch[i - 1][j - 1];
                    } else if (p.charAt(j - 1) == '*') {
                        if (j < 2) {
                            continue;
                        }
                        // 试试可能a*表示为empty的时候你就成功了。
                        isMatch[i][j] = isMatch[i][j - 2];
                        // 当a*表示为一次或多次时,你还有一次额外成功的机会。
                        if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.')  {
                            isMatch[i][j] = isMatch[i][j] || isMatch[i - 1][j];
                        }
                    }
                }
            }
            return isMatch[s.length()][p.length()];
            
        }
    }
  • 相关阅读:
    HDFS高阶
    Flume学习笔记
    Yarn学习笔记
    二进制中1的个数
    二叉搜索树的后序遍历
    空指针
    web第十天总结
    绩效考核系统
    制作流程图,activity,好不容易找到的
    职业规划
  • 原文地址:https://www.cnblogs.com/jasminemzy/p/9577964.html
Copyright © 2011-2022 走看看