leetcode题解-10. Regular Expression Matching

来源:互联网 发布:英国贵族知乎 编辑:程序博客网 时间:2024/06/06 03:35

题意:正则匹配。比较两个字符串是否一致,这里有两个特殊符号 “.” 和 “” ,”.”可以匹配单个字符,而””可以匹配任意个与前一字符相同的字符。

分析:按照Solution中的思路,有递归和动态规划两种方法。而这道题使用动态规划不仅方便易懂,而且代码也非常整洁。首先看一下伪代码:

这里写图片描述

看起来很精简,但是要真正理解,我还是用了一下午的时间。下面我们从头开始说明一下构造dp二维数组的过程。

举例:
s = “aab”
p = “c*a*b”

要采用动态规划方法,肯定就是用空间换时间。那么我们申请一个二维数组dp:

boolean[][] dp = new boolean[s.length()+1][p.length()+1];

dp的初始化:

声明:下文中的索引都是从1开始,如p=c*a*b,那么p[0]=”,p[1]=’c’…..

这里写图片描述

首先,初始化第一列。只有dp[0][0] = True,dp[0][j]=False (j = 1,2,3)。因为对于p=”“来说,只有s=”“可以匹配到,其他的s匹配不到。

其次,初始化第一列。第一列的初始化就是对于s=”“来说,哪一个p能匹配到。对上图而言,当j=2和j=4时,能匹配到空字符。值得一提的是,在p中,不能是第一个出现的字符,所以无需进行检查。

for (int i = 1; i <= p.length(); i++) {                if (p.charAt(i - 1) == '*') {                    // * 不能是第一个出现的字符,所以无需进行检查                    dp[0][i] = dp[0][i - 2];                }            }

dp的动态方程:

1、 对于特定的i和j,s和p中的字符能匹配。举例:s=abcd,p=abed,s[4]=p[4]=d,此时s和p是否匹配,就要看前面s[1]….s[3]=abc和p[1]…p[3]=abe是否匹配。此时满足的动态方程就是:

if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.'){      dp[i][j] = dp[i - 1][j - 1];}

2、对于特定的i和j,s和p中的字符不能匹配,即s[i]!=p[j]并且p[j]!=’.’。但是如果p[j]=,又会分为如下两种情况:

2.1、当p中前面的字母与p中的字母不匹配时,即s=abcd,p=abcde,此时s[4]=d!=s[5]=e,那么s[1]….s[4]=abcd和p[1]….p[6]=abcde是否匹配,就要看s[1]….s[4]=abcd和p[1]….p[4]=abcd是否匹配。

if(s.charAt(i - 1) != p.charAt(j - 2) && p.charAt(j - 2) != '.'){                            dp[i][j] = dp[i][j - 2];                        }

2.2、当p中前面的字母与p中的字母匹配时,又有三种情况:

2.2.1、
s=abcdd,p=abcd,s[5]=d,p[5]=时,s和p是否匹配就要看s[1]….s[4]和p[1]….p[5]是否匹配,即:

dp[i][j] = dp[i - 1][j]

2.2.2、
s=abcd,p=abcd,s[4]=d,p[5]=时,s和p是否匹配就要看s[1]….s[4]和p[1]….p[4]是否匹配,即:

dp[i][j] = dp[i][j - 1]

2.2.3、
s=abc,p=abc.,s[3]=c,p[5]=时,s和p是否匹配就要看s[1]….s[3]和p[1]….p[3]是否匹配,即:

dp[i][j] = dp[i][j - 2]

对于2.2.1、2.2.2、2.2.3三种情况只要满足一种即可。所以当p中前面的字母与p中的字母匹配时:

dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];

通过对上述逻辑的分析,填出dp初始化图中的空白部分应该也不在话下。感兴趣的同学可以自己加断点调试一下。所以总体的代码为:

//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") → trueclass Solution {     public boolean isMatch(String s, String p){         if (s == null || p == null) {                return false;            }            boolean[][] dp = new boolean[s.length()+1][p.length()+1];            // 初始化 先初始化第一列            dp[0][0] = true;            // 在初始化第一行            for (int i = 1; i <= p.length(); i++) {                if (p.charAt(i - 1) == '*') {                    // * 不能使第一个出现的字符,所以无需进行检查                    dp[0][i] = dp[0][i - 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) == '.'){                        dp[i][j] = dp[i - 1][j - 1];                    }else if(p.charAt(j - 1) == '*'){                        if(s.charAt(i - 1) != p.charAt(j - 2) && p.charAt(j - 2) != '.'){                            dp[i][j] = dp[i][j - 2];                        }else{                            dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];                        }                    }                }            }            return dp[s.length()][p.length()];        }    public static void main(String[] args) {        String s = "f";        String p = "f.*";        Solution sl = new Solution();        System.out.println(sl.isMatch(s, p));    }}
原创粉丝点击