leetcode刷题笔记十 正则表达式 Scala版本
leetcode刷题笔记十 正则表达式 Scala版本
源地址:leetcode刷题笔记十 正则表达式 Scala版本
问题描述:
Given an input string (
s
) and a pattern (p
), 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).
Note:
s
could be empty and contains only lowercase lettersa-z
.p
could be empty and contains only lowercase lettersa-z
, and characters like.
or*
.
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
简要思路分析:
首先对正则表达式进行分析,对于s串,其对应小写字母a-z;对于p串,其对应小写字母a-z,.或者*。因为对于样式,每个字符有三种可能,我们对三种可能进行分析。
s[i] : 字符串s第i个字符的位置 p[j]:样式串p第j个字符的位置
match[i]:为第i个状态的正则匹配情况
(1)p[j] 为一个字母
设 s="aa" p="ab"
s[0] == p[0] ==> match[0] = T
s[1] != p[1] ==> match[1] = (match[0] && (s[1] == p[1])) => F
(2)p[j] = '.',这里'.'代表'.' 匹配任意单个字符
设s="aa", p="a."
由于 '.'可以匹配任意单个字符,当p[j]='.',我们不需要考虑对应的s串的字符是什么。
s[0] == p[0] ==> match[0] = T
s[1] != p[1] 但 p[1] ='.' ==> match[1] = (match[0] && (p[1] == '.')) => T
(3) p[j] = '*', *匹配零个或多个前面的那一个元素
因为'*'存在两种情况,0次匹配或者多次匹配
就0次匹配而言,视其对于'*'号前一字符的影响也存在两种情况。
【1】0次匹配,且对前一字符消失
设s="a", p="ac" 这里p[2]='*',且'*'令前一个字符C消失,这里match[0][2] = match[0][0] j向前移动两位
【2】 0次匹配,不影响前一字符
设s="a",p="ac*" 或者 s = "a" , p=".*", 这里p[1]="*"
match[0][2] = match[0][0] ==> if ((s[0] == p[0]) || p[0] == '.')
【3】多次匹配,不影响前一字符
设s="aa",p="a*" ==> match[1][1] = match[1][0]
总结状态方程
match[i][j] = match[i-1][j-1] if p[j-1] != '*' && ((s[i-1] == p[j-1]) || p[j-1] == '.' )
match[i][j] = match[i][j-2] if p[j-1] == '*' && (s[i-1] != p[j-2])
match[i][j] = match[i-1][j] || match[i][j-2] if p[j-1] == '*' && ((s[i-1] != p[j-2]) || p[j-2] == '.')
根据状态方程,可以通过回溯法或者动态规划实现
代码补充:
1.回溯法
object Solution { def isMatch(s: String, p: String): Boolean = { if (p.length <= 0 ) return s.length <= 0 var imatch:Boolean = (s.length > 0 &&(s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')) //println("imatch: " + imatch) if (p.length > 1 && p.charAt(1) == '*'){ return isMatch(s, p.substring(2)) ||( imatch && isMatch(s.substring(1), p)) } else{ return imatch && (isMatch(s.substring(1),p.substring(1))) } } }
2.动态规划
object Solution { def isMatch(s: String, p: String): Boolean = { var dp = Array.ofDim[Boolean](s.length+2, p.length+2) //var dp = Array.fill(s.length, p.length)(false) val sStr = ' ' + s val pStr = ' ' + p if (pStr.length <= 0) return sStr.length<=0 dp(0)(0) = true for (i <- 1 to sStr.length){ for(j <- 1 to pStr.length){ //println("----------------------------") //println("i: "+i) //println("j: "+j) //println("p(j-1): " + pStr.charAt(j-1)) //println("s(i-1): " + sStr.charAt(i-1)) if (pStr.charAt(j-1) != '*'){ if (pStr.charAt(j-1) == sStr.charAt(i-1) || pStr.charAt(j-1) == '.'){dp(i)(j) = dp(i-1)(j-1)} else {dp(i)(j)=false} //println("!*") //println("dp(i-1)(j-1): "+dp(i-1)(j-1)) } else{ if (pStr.charAt(j-2) == sStr.charAt(i-1) || pStr.charAt(j-2) == '.') dp(i)(j) = dp(i)(j-2) || dp(i-1)(j) else dp(i)(j) = dp(i)(j-2) //dp(i)(j) = dp(i)(j-2)||dp(i-1)(j) //println("*") //println("dp(i)(j-2): "+dp(i)(j-2)) //println("dp(i-1)(j): "+dp(i-1)(j)) } //println("dp(i)(j): " + dp(i)(j)) //println("dp(i)(j): " + dp(i)(j)) } } return dp(s.length+1)(p.length+1) } }
func isMatch(s string, p string) bool {
n := len(s)
m := len(p)
s = " " + s
p = " " + p
arr := make([][]bool, n+1)
for i := 0; i < len(arr); i++ {
arr[i] = make([]bool, m+1)
}
//var arr = [n+1][m+1]bool 报错 无法直接在二维数组创建时传变量
arr[0][0] = true
for i := 0; i <= n; i++ {
for j := 1; j <= m; j++ {
if j+1 <= m && p[j+1] == '*' {
continue
}
if i > 0 && p[j] != '*' {
arr[i][j] = arr[i-1][j-1] && (s[i] == p[j] || p[j] == '.')
} else if p[j] == '*' {
arr[i][j] = arr[i][j-2] || (i > 0 && arr[i-1][j] && (s[i] == p[j-1] || p[j-1] == '.'))
}
}
}
return arr[n][m]
}