1. 程式人生 > >[Swift]LeetCode10. 正則表示式匹配 | Regular Expression Matching

[Swift]LeetCode10. 正則表示式匹配 | Regular Expression Matching

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 letters a-z.
  • p could be empty and contains only lowercase letters a-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*"))