[Swift]LeetCode10. 正则表达式匹配 | Regular Expression Matching
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9883662.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
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 precedeng 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
) 和一个字符模式 (p
)。实现支持 '.'
和 '*'
的正则表达式匹配。
'.' 匹配任意单个字符。 '*' 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s
) ,而不是部分字符串。
说明:
s
可能为空,且只包含从a-z
的小写字母。p
可能为空,且只包含从a-z
的小写字母,以及字符.
和*
。
示例 1:
输入: s = "aa" p = "a" 输出: false 解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入: s = "aa" p = "a*" 输出: true 解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 "aa"。
示例 3:
输入: s = "ab" p = ".*" 输出: true 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入: s = "aab" p = "c*a*b" 输出: true 解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入: s = "mississippi" p = "mis*is*p*." 输出: false
32ms
1 enum Result { 2 case TRUE,FALSE 3 } 4 class Solution { 5 var memo:[[Result?]] = [[Result?]]() 6 func isMatch(_ s: String, _ p: String) -> Bool { 7 let col:Int = p.count + 1 8 let row:Int = s.count + 1 9 memo = [[Result?]](repeating: [Result?](repeating: nil, count: col), count: row) 10 return dp(0, 0, s, p) 11 } 12 13 func dp(_ i:Int,_ j:Int,_ text:String,_ pattern:String) -> Bool 14 { 15 if memo[i][j] != nil 16 { 17 return memo[i][j] == Result.TRUE 18 } 19 var ans:Bool 20 if j == pattern.count 21 { 22 ans = i == text.count 23 } 24 else 25 { 26 var first_match:Bool = i < text.count && 27 (pattern.charAt(j) == text.charAt(i) || 28 pattern.charAt(j) == ".") 29 if j + 1 < pattern.count && pattern.charAt(j+1) == "*" 30 { 31 ans = dp(i, j+2, text, pattern) || first_match && dp(i+1, j, text, pattern) 32 } 33 else 34 { 35 ans = first_match && dp(i+1, j+1, text, pattern) 36 } 37 } 38 memo[i][j] = ans ? Result.TRUE : Result.FALSE 39 return ans 40 } 41 } 42 extension String { 43 //获取指定索引位置的字符,返回为字符串形式 44 func charAt(_ num:Int) -> String 45 { 46 guard num < self.count else { 47 assertionFailure("Index out of range!") 48 return String() 49 } 50 let index = self.index(self.startIndex,offsetBy: num) 51 return String(self[index]) 52 } 53 }
16ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 let s = Array(s), p = Array(p) 4 var rec: [[Bool]] = Array(repeating: Array(repeating: false, count: p.count + 1), count: s.count + 1) 5 6 rec[0][0] = true 7 for i in 0..<p.count { 8 if p[i] == "*" { 9 rec[0][i + 1] = rec[0][i - 1] 10 } 11 } 12 13 for i in 0..<s.count { 14 for j in 0..<p.count { 15 if p[j] != "*" { 16 if rec[i][j] { 17 if p[j] == "." || p[j] == s[i] { 18 rec[i + 1][j + 1] = true 19 } 20 } 21 } else { 22 if rec[i + 1][j - 1] { 23 rec[i + 1][j + 1] = true 24 } else if rec[i][j - 1] || rec[i][j + 1] { 25 if p[j - 1] == s[i] || p[j - 1] == "." { 26 rec[i + 1][j + 1] = true 27 } 28 } 29 } 30 } 31 } 32 33 return rec[s.count][p.count] 34 } 35 }
20ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 let arrayS = Array(s.characters), 4 lenS = arrayS.count, 5 arrayP = Array(p.characters), 6 lenP = arrayP.count 7 var dp = [[Bool]](repeating: [Bool](repeating: false, count: lenP + 1), count: lenS + 1) 8 dp[0][0] = true 9 for i in 0..<lenP { 10 if arrayP[i] == "*" && dp[0][i - 1] { 11 dp[0][i+1] = true 12 } 13 } 14 for i in 0..<lenS { 15 for j in 0..<lenP { 16 if arrayP[j] == "." { 17 dp[i+1][j+1] = dp[i][j] 18 } 19 if arrayP[j] == arrayS[i] { 20 dp[i+1][j+1] = dp[i][j] 21 } 22 if arrayP[j] == "*" { 23 if arrayP[j-1] != arrayS[i] && 24 arrayP[j-1] != "." { 25 dp[i+1][j+1] = dp[i+1][j-1] 26 } else { 27 dp[i+1][j+1] = (dp[i+1][j] || dp[i][j+1] || dp[i+1][j-1]) 28 } 29 } 30 } 31 } 32 return dp[lenS][lenP] 33 }
24ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 var dp = [[Bool]](repeating: [Bool](repeating: false, count: p.count + 1), count: s.count + 1) 4 // Initial condition: both empty, it's a match. 5 dp[0][0] = true 6 let sChars = Array(s) 7 let pChars = Array(p) 8 for j in 0..<p.count { 9 if pChars[j] == "*" && dp[0][j - 1] { 10 dp[0][j + 1] = true 11 } 12 } 13 for i in 0..<s.count { 14 let sChar = sChars[i] 15 for j in 0..<p.count { 16 let pChar = pChars[j] 17 if (sChar == pChar || pChar == ".") { 18 // If s[i] == p[j] or p[j] == '.', check if dp[i - 1][j - 1] matches. 19 dp[i + 1][j + 1] = dp[i][j] 20 } else if pChar == "*" { 21 // If p[j] == '*', then there are two situations. 22 // j - 1 j 23 // p: ... x '*' ... 24 // s: ... z y ... 25 // i - 1 i 26 if pChars[j - 1] != sChars[i] && pChars[j - 1] != "." { 27 // If x != y and x != '.', we can only count x '*' for 0 times, so check if the previous char before x matches y 28 // Here i is guaranteed >= 2 as '*' cannot appear at index 0 in p. 29 dp[i + 1][j + 1] = dp[i + 1][j - 1] 30 } else { 31 // If x == y or x == '.', then there are three situations. 32 dp[i + 1][j + 1] = dp[i + 1][j - 1] // x appears zero times 33 || dp[i + 1][j] // x appears one time to match y 34 || dp[i][j + 1] // x appears multiple times: y should be part of match to x '*', so check if char before y is a match to x '*' 35 } 36 } 37 } 38 } 39 return dp[s.count][p.count] 40 } 41 }
28ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 let sChars = s.utf8CString 4 let pChars = p.utf8CString 5 var dp = Array(repeating: Array(repeating: false, count: pChars.count), count: sChars.count) 6 dp[0][0] = true 7 8 for i in 0...pChars.count-1 { 9 dp[0][i] = i == 0 || i > 1 && dp[0][i-2] && pChars[i-1] == 42 10 } 11 12 for i in 0...sChars.count-1 { 13 for j in 0...pChars.count-1 { 14 guard j > 0 else { 15 continue 16 } 17 18 let pCurrent = pChars[j - 1] 19 20 if pCurrent != 42 { 21 dp[i][j] = i > 0 && dp[i-1][j-1] && (pCurrent == 46 || pCurrent == sChars[i - 1]) 22 } else { 23 dp[i][j] = dp[i][j-2] || i > 0 && j > 1 && (sChars[i-1] == pChars[j-2] || pChars[j-2] == 46) && dp[i-1][j] 24 } 25 } 26 } 27 28 return dp[sChars.count-1][pChars.count-1] 29 30 31 } 32 }
32ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 let text = Array(s) 4 let patter = Array(p) 5 var dp = [[Bool]](repeating: [Bool](repeating: false, count: patter.count+1), count: text.count+1) 6 dp[text.count][patter.count] = true 7 for i in stride(from: text.count, to: -1, by: -1) { 8 for j in stride(from: patter.count-1, to: -1, by: -1) { 9 let first_match = (i < text.count && (patter[j] == text[i] || patter[j] == ".")); 10 if j + 1 < patter.count && patter[j+1] == "*" { 11 dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j]; 12 } else { 13 dp[i][j] = first_match && dp[i+1][j+1]; 14 } 15 } 16 } 17 return dp[0][0]; 18 } 19 }
36ms
1 class Solution { 2 func isMatch(_ s: String, _ p: String) -> Bool { 3 guard !p.isEmpty else { 4 guard s.isEmpty else { return false } 5 return true 6 } 7 8 let s = Array(s) 9 let p = Array(p) 10 11 // matchMatrix[i][j] first i chars in s match p[0...j] 12 var match = Array(repeating: Array(repeating: false, count: p.count), count: s.count + 1) 13 14 // init for i = 0 15 for j in 1..<p.count { 16 if p[j] == "*" { 17 match[0][j] = j > 1 ? match[0][j-2] : true 18 } 19 } 20 21 guard !s.isEmpty else { return match[0][p.count - 1] } 22 for i in 1...s.count { 23 if i == 1 { 24 match[1][0] = p[0] == "." ? true : s[0] == p[0] 25 } 26 for j in 1..<p.count { 27 switch p[j] { 28 case ".": 29 match[i][j] = match[i - 1][j - 1] 30 case "*": 31 if p[j - 1] == "." || s[i - 1] == p[j - 1] { // match preceding element 32 match[i][j] = match[i - 1][j] || match[i - 1][j - 1] 33 } 34 35 guard !match[i][j] else { continue } 36 if j > 1 { // match zero element 37 match[i][j] = match[i][j - 2] 38 } 39 case s[i - 1]: 40 match[i][j] = match[i - 1][j - 1] 41 default: 42 continue 43 } 44 } 45 } 46 return match[s.count][p.count - 1] 47 } 48 49 }
44ms
1 struct Token { 2 var char:Character 3 var isStar:Bool 4 } 5 6 class Solution { 7 func isMatch(_ s: String, _ p: String) -> Bool{ 8 let sChars = Array(s), pChars = Array(p) 9 var dp = Array(repeating: Array(repeating: false, count: pChars.count + 1), count: sChars.count + 1) 10 dp[0][0] = true 11 12 for i in 0...pChars.count { 13 // jump over "" vs. "x*" case 14 dp[0][i] = i == 0 || i > 1 && dp[0][i - 2] && pChars[i - 1] == "*" 15 } 16 17 for i in 0...sChars.count { 18 for j in 0...pChars.count { 19 guard j > 0 else { 20 continue 21 } 22 23 let pCurrent = pChars[j - 1] 24 25 if pCurrent != "*" { 26 dp[i][j] = i > 0 && dp[i - 1][j - 1] && (pCurrent == "." || pCurrent == sChars[i - 1]) 27 } else { 28 dp[i][j] = dp[i][j - 2] || i > 0 && j > 1 && (sChars[i - 1] == pChars[j - 2] || pChars[j - 2] == ".") && dp[i - 1][j] 29 } 30 } 31 } 32 33 return dp[sChars.count][pChars.count] 34 } 35 }
80ma
1 class Solution { 2 3 var visited = [[Bool]]() 4 5 func isMatch(_ s: String, _ p: String) -> Bool { 6 for i in 0..<s.count { 7 var line = [Bool]() 8 for j in 0..<p.count { 9 line.append(false) 10 } 11 visited.append(line) 12 } 13 return rec(s, p, 0, 0) 14 } 15 16 func rec(_ sStr: String, _ pStr: String, _ sindex: Int, _ pindex:Int) -> Bool { 17 let s = Array(sStr) 18 let p = Array(pStr) 19 20 if s.count>sindex && p.count>pindex { 21 if visited[sindex][pindex] { 22 return false 23 } else { 24 visited[sindex][pindex] = true 25 } 26 } 27 28 if sindex >= s.count && pindex >= p.count { 29 return true 30 } 31 32 if pindex < p.count-1 && p[pindex+1] == "*" { 33 if p[pindex] == "." { 34 for i in 0..<s.count-sindex { 35 if rec(sStr,pStr,sindex+i,pindex+2) { 36 return true 37 } 38 } 39 if rec(sStr, pStr, s.count, pindex+2) { 40 return true 41 } 42 } else { 43 var i = 0 44 while sindex+i < s.count && s[sindex+i] == p[pindex] { 45 if rec(sStr, pStr, sindex+i, pindex+2) { 46 return true 47 } 48 i += 1 49 } 50 if rec(sStr, pStr, sindex+i, pindex+2) { 51 return true 52 } 53 } 54 } else { 55 if pindex<p.count && sindex<s.count && (p[pindex] == s[sindex] || p[pindex] == ".") { 56 return rec(sStr, pStr , sindex+1, pindex+1) 57 } else { 58 return false 59 } 60 } 61 return false 62 } 63 } 64 65 //测试 66 let s = Solution() 67 68 print(s.isMatch("aa", "a*"))