正則表達式匹配
1.題目
給你一個字符串 s 和一個字符規律 p,請你來實現一個支持 ‘.’ 和 ‘*’ 的正則表達式匹配。
‘.’ 匹配任意單個字符
‘*’ 匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋 整個 字符串 s的,而不是部分字符串。
說明:
- s 可能爲空,且只包含從 a-z 的小寫字母。
- p 可能爲空,且只包含從 a-z 的小寫字母,以及字符 . 和 *。
示例 1:
輸入:
s = “aa”
p = “a”
輸出: false
解釋: “a” 無法匹配 “aa” 整個字符串。
示例 2:
輸入:
s = “aa”
p = “a*”
輸出: true
解釋: 因爲 ‘*’ 代表可以匹配零個或多個前面的那一個元素, 在這裏前面的元素就是 ‘a’。因此,字符串 “aa” 可被視爲 ‘a’ 重複了一次。
示例 3:
輸入:
s = “ab”
p = “."
輸出: true
解釋: ".” 表示可匹配零個或多個(’*’)任意字符(’.’)。
示例 4:
輸入:
s = “aab”
p = “cab”
輸出: true
解釋: 因爲 ‘*’ 表示零個或多個,這裏 ‘c’ 爲 0 個, ‘a’ 被重複一次。因此可以匹配字符串 “aab”。
示例 5:
輸入:
s = “mississippi”
p = “misisp*.”
輸出: false
題目模板
/**
* @param {string} s
* @param {string} p
* @return {boolean}
*/
var isMatch = function(s, p) {
};
2.思路分析
這裏的有無模式指的是是否有匹配符”*“或“.”
3.所用到的方法
主要是正則,看其他小夥伴還用到了動態規劃、有向圖、圖的深度遍歷、自動機,6p
4.題解及優化
課程解法
課程視頻源碼通不過。。。
var isMatch = function(s, p) {
// 對模式變量進行正則篩選
let modeArr = p.match(/([a-z.]\*)|([a-z]+(?=([a-z.]\*)|$))/g)
let cur = 0
let strLen = s.length
for (let i = 0, len = modeArr.length, m; i < len; i++) {
// 對於模式分爲三類,.*|a*|cdef
m = modeArr[i].split('')
// 如果第二位是*表示是有模式的
if (m[1] === '*') {
if (m[0] === '.') {
cur = strLen
break
} else {
while (s[cur] === m[0]) {
cur++
}
}
} else {
for (let j = 0, jl = m.length; j < jl; j++) {
if (m[j] !== s[cur]) {
return false
} else {
cur++
}
}
}
}
return cur === strLen
}
調試後:
var isMatch = function (s, p) {
p = p.split('')
p.push('a*')
p = p.join('')
console.log(p)
s = s.split('')
s.push('aa')
s = s.join('')
console.log(s)
// 對模式變量進行正則篩選
let modeArr = p.match(/([a-z.]\*)|([a-z]+(?=([a-z.]\*)|$))/g)
let cur = 0
let strLen = s.length
for (let i = 0, len = modeArr.length, m; i < len; i++) {
// 對於模式分爲三類,.*|a*|cdef
m = modeArr[i].split('')
// 如果第二位是*表示是有模式的
if (m[1] === '*') {
if (m[0] === '.') {
cur = strLen
break
} else {
while (s[cur] === m[0]) {
cur++
}
}
} else {
for (let j = 0, jl = m.length; j < jl; j++) {
if (m[j] !== s[cur]) {
return false
} else {
cur++
}
}
}
}
return cur === strLen
}
通過在s和p後添加*或其他字母都沒有效果,應該是“.”的問題,代碼進不去m[0] === '.'
課程後面提供的源碼能夠通過
var isMatch = function (s, p) {
// 邊界情況,如果s和p都爲空,說明處理結束了,返回true,否則返回false
if (p.length <= 0) {
return !s.length
}
// 判斷p模式字符串的第一個字符和s字符串的第一個字符是不是匹配
let match = false
if (s.length > 0 && (p[0] === s[0] || p[0] === '.')) {
match = true
}
// p有模式的
if (p.length > 1 && p[1] === '*') {
// 第一種情況:s*匹配0個字符
// 第二種情況:s*匹配1個字符,遞歸下去,用來表示s*匹配多個s
return isMatch(s, p.slice(2)) || (match && isMatch(s.slice(1), p))
} else {
return match && isMatch(s.slice(1), p.slice(1))
}
}
其他小夥伴的解法
var isMatch = function (s, p) {
return new RegExp('^' + p + '$').test(s)
}
不同答案,涉及較廣,值得深入探索,待續。。。