- Difficulty: Hard
- Related Topics: String, Dynamic Programming, Backtracking
- Link: https://leetcode.com/problems/regular-expression-matching/
Description
Given an input string (s
) and a pattern (p
), implement regular expression matching with support for '.'
and '*'
where:
给定一输入字符串 s
和匹配规则 p
,实现一个正则表达式引擎,要求能支持 '.'
和 '*'
的匹配,其中:
'.'
Matches any single character.
'.'
匹配任意单个字符。'*'
Matches zero or more of the preceding element.
'*'
将其前面一个元素匹配 0 或多次。
The matching should cover the entire input string (not partial).
匹配应该针对整个字符串进行(非部分)。
Examples
Example 1
Input: s = "aa", p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Example 2
Input: s = "aa", p = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Example 3
Input: s = "ab", p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Example 4
Input: s = "aab", p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab".
Example 5
Input: s = "mississippi", p = "mis*is*p*."
Output: false
Constraints
0 <= s.length <= 20
0 <= 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.
Solution
这题的做法有点像最长公共子序列。定义 dp(i, j)
表示 s[0, i]
和 p[0, j]
的匹配结果(字符串下标从 1 开始):
-
dp(0, 0) = true
(空串匹配空串); -
若
s[i] == p[j]
,显然,dp(i, j) = dp(i - 1, j - 1)
; -
若
p[j] == '.'
,自然也能匹配,dp(i, j) = dp(i - 1, j - 1)
; -
若
p[j] == '*'
,则又有以下几种情况:-
s[i] != p[j]
:则此时不能匹配任何字符,dp(i, j) = dp(i, j - 2)
-
s[i] == p[j]
或p[j - 1] == '.'
:此时以下三种情况都可以匹配-
dp(i, j) = dp(i - 1, j)
(匹配多个字符) -
dp(i, j) = dp(i, j - 1)
(匹配一个字符) -
dp(i, j) = dp(i, j - 2)
(不匹配任何字符)
-
-
代码如下
class Solution {
fun isMatch(s: String, p: String): Boolean {
val dp = Array(s.length + 1) { BooleanArray(p.length + 1) }
dp[0][0] = true
for (i in p.indices) {
if (p[i] == '*' && dp[0][i - 1]) {
dp[0][i + 1] = true
}
}
for (i in s.indices) {
for (j in p.indices) {
doMatching(s, i, p, j, dp)
}
}
return dp.last().last()
}
private fun doMatching(
s: String,
i: Int,
p: String,
j: Int,
dp: Array<BooleanArray>
) {
if (p[j] == '.') {
dp[i + 1][j + 1] = dp[i][j]
}
if (p[j] == s[i]) {
dp[i + 1][j + 1] = dp[i][j]
}
if (p[j] == '*') {
if (p[j - 1] != s[i] && p[j - 1] != '.') {
dp[i + 1][j + 1] = dp[i + 1][j - 1]
} else {
dp[i + 1][j + 1] = (dp[i + 1][j] || dp[i][j + 1] || dp[i + 1][j - 1])
}
}
}
}