[LeetCode] 10. Regular Expression Matching

Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where:

  • '.' Matches any single character.
  • '*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = "*"
Output: true
Explanation: '*' matches any sequence.

Example 3:

Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.

Example 4:

Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".

Example 5:

Input:
s = "acdcb"
p = "a*c?b"
Output: false

Constraints:

  • 1 <= s.length <= 20
  • 1 <= p.length <= 30
  • s contains only lowercase English letters.
  • p contains only lowercase English letters, '.', and '*'.
  • It is guaranteed for each appearance of the character '*', there will be a previous valid character to match.

正则表达式匹配。

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给一个字符串S和一个字符规律P,请你完成S和P的正则匹配。规则如下,点可以表示/替换任何字符;星号可以代替0个或多个之前的字符。

这个题是一个二维 DP 题。这个题 DP 的含义不难想,难的是如何处理好各种 case。这里我们需要明确 dp[i][j] 的含义,是 s 的前 i 个字符与 p 的前 j 个字符是否 match。为了看 s 的前 i 个字符与 p 的前 j 个字符是否 match,比较直观的想法就是去看他们各自之前一个位置的 DP 情况,即 dp[i - 1][j - 1],但是对于当前位置,会有如下几种情况需要考虑。参考了LC中文网一个大神的总结

1. 如果 p[j] == s[i],s 中当前字母 == p 中当前字母,那么 dp[i][j] = dp[i-1][j-1]

2. 如果p[j] != s[i],即当前遍历到的字符跟模式不匹配

2.1. p[j] == "." : dp[i][j] = dp[i-1][j-1],因为点可以替换任何字符,只要去看之前那一位的字符是否匹配即可。这个 case 几乎等同于第一个 case

2.2. p[j] ==" * ",这个又需要细分成以下两种情况。因为星号可以代替0个多个在他之前的那个字符,所以需要看 p[j - 1] 和 s[i] 的情况

2.2.1. p[j-1] != s[i] : dp[i][j] = dp[i][j-2]

这里设想的是星号去掉了他自己和他自己之前的那个字符,比如这个例子,s = ab, p = abc*

2.2.2. p[j-1] == s[i] or p[j-1] == "."。星号前面那个字符,能匹配 s[i],或者星号前面那个字符是万能的。因为星号 + 点就等同于两个点,只要看再前面的部分是否匹配即可。比如s = aa, p = a*

时间O(mn)

空间O(mn)

Java实现

 1 class Solution {
 2     public boolean isMatch(String s, String p) {
 3         // corner case
 4         int m = s.length();
 5         int n = p.length();
 6         boolean[][] dp = new boolean[m + 1][n + 1];
 7         dp[0][0] = true;
 8 
 9         // s为空,p不为空,由于*可以匹配0个字符,所以有可能为true
10         for (int i = 2; i <= n; i++) {
11             if (p.charAt(i - 1) == '*') {
12                 dp[0][i] = dp[0][i - 2];
13             }
14         }
15 
16         for (int i = 1; i <= m; i++) {
17             for (int j = 1; j <= n; j++) {
18                 char sc = s.charAt(i - 1);
19                 char pc = p.charAt(j - 1);
20                 // 文本串和模式串末位字符能匹配上
21                 if (sc == pc || pc == '.') {
22                     dp[i][j] = dp[i - 1][j - 1];
23                 }
24                 // 模式串末位是 *
25                 else if (pc == '*') {
26                     // 星号也许可以去抵消前一个字母
27                     if (dp[i][j - 2]) {
28                         dp[i][j] = true;
29                     }
30                     // 模式串里星号的前一个字符能够跟文本串的末位匹配上
31                     // 或者星号的前一个字符是点,星号就可以抵消点
32                     else if (p.charAt(j - 2) == sc || p.charAt(j - 2) == '.') {
33                         dp[i][j] = dp[i - 1][j];
34                     }
35                 }
36             }
37         }
38         return dp[m][n];
39     }
40 }

 

LeetCode 题目总结

posted @ 2020-05-09 08:10  CNoodle  阅读(413)  评论(0编辑  收藏  举报