LeetCode10正则表达式

考研完之后一直很浮躁,也没做啥事儿,现在疫情这么严重,出不了家门,初始公布成绩也推迟了,还有十来天就要出成绩了,呼……先做毕设写算法,出成绩之后再打算趴。

10 正则表达式

题目链接

之前试着提交过这个题目,但是没过,今天补上。

解题报告里有两种方法,回溯,动态规划。自己写的时候用回溯,但是代码及其不简洁而且考虑也不周全。解题报告里的回溯代码可真是清爽。

回溯法

如果没有符号 * 的存在这个题目就会很简单,* 符号代表匹配前一个字符0次或者多次,另外 . 符号表示着任意字符。

这样一来 * 符号有两种情况:

  • 匹配前一个字符 0 次
  • 匹配前一个字符 多 次

所以,分情况来看:( i, j 分别表示s,p字符串的位置)

  1. p[j+1] != '*' p[i] == s[i] || p[j] == '.'
    也就是说 s[i] p[j] 可以匹配,并且p[j]后面的字符不是* :令s[i+1]和p[j+1]后面的字符串去匹配
  2. p[j+1] == '*'
    这时候就要分两种情况来看,
    匹配0次的时候:去比较s[i]和p[j+2]之后的字符串,是否匹配成功
    匹配多次的时候:s[i]==p[j] 且 s[i+1]和p[j]之后的字符串可以匹配成功
代码:
	public boolean isMatch(String s, String p) {
        if (p.isEmpty()) return s.isEmpty(); //两者为“” 则为true

		// 第一个字符是否匹配
        boolean first = (!s.isEmpty()) && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');

        if (p.length() >= 2 && p.charAt(1) == '*') {//有*的时候
            // || 前面为匹配0次的情况 “aab, a*c*b” 
            // || 后面为匹配多次的情况 “aaab, a*b”
            return (isMatch(s, p.substring(2))) || (first && isMatch(s.substring(1), p));
        } else {
            return first && isMatch(s.substring(1), p.substring(1));
        }
    }

动态规划

dp[i][j]表示s前i个字符是否可以被p的前j个字符匹配成功。
根据dp[i-1][j-1]来判断dp[i][j]

  1. p[j] != '*'
    p[j] == s[i] || p[j] == '.' : p[i][j] = p[i-1][j-1]
  2. p[j] == '*'
    p[j-1] != s[i] : s[i]* 前面的字符匹配不上, 但并不代表是匹配失败,还有可能*前的字符匹配0次,这是需要看dp[i][j-2]的情况:dp[i][j] = dp[i][j-2]
    p[j-1] == s[i] : 同 * 前的字符匹配上,但这也不能代表s的前i个字符可以被p的前j个字符匹配,此时还是两种情况:匹配0次,即dp[i][j-2]的情况;匹配多次,即dp[i-1][j]的情况;两种情况有一种成功,即成功
代码:
    public boolean isMatch(String s, String p) {
        boolean[][] dp = new boolean[s.length()+1][p.length()+1];
        dp[0][0] = true;
        // 相当于初始 "" 被p匹配的情况
        for (int i = 0; i < p.length(); i++) { 
            if (p.charAt(i)=='*' && dp[0][i-1]) dp[0][i+1] = true;
        }
		
        for (int i = 0; i < s.length(); i++) {
            for (int j = 0; j < p.length(); j++) {
                //  s[i] 可以和 p[j] 匹配的情况,看dp前面
                if (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'){
                    dp[i+1][j+1] = dp[i][j];
                }
                if (p.charAt(j) == '*'){
                	// s[i] 和 p[j] 前的字符匹配不上 考虑匹配0次的情况
                    if (p.charAt(j-1) != s.charAt(i) && p.charAt(j-1) != '.'){
                        dp[i+1][j+1] = dp[i+1][j-1];
                    }else{
                    //s[i] 和 p[j] 前的字符匹配上 需要考虑匹配0次和匹配多次的情况 
                        dp[i+1][j+1] = dp[i+1][j-1] || dp[i][j+1];
                    }
                }
            }
        }

        return dp[s.length()][p.length()];
    }
代码中的dp[i][j] 和 s[i] p[j] 中的i和j分别代表各自在各种中的索引
发布了151 篇原创文章 · 获赞 43 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_38595487/article/details/104254718