java 字符正则匹配算法_算法之字符串——正则表达式匹配
難度 困難
請實現一個函數用來匹配包含’. ‘和’*‘的正則表達式。模式中的字符’.’表示任意一個字符,而’*‘表示它前面的字符可以出現任意次(含0次)。在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串”aaa”與模式”a.a”和”abaca”匹配,但與”aa.a”和”ab*a”均不匹配。
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 = “c*a*b”
輸出: true
解釋: 因為 ‘*’ 表示零個或多個,這里 ‘c’ 為 0 個, ‘a’ 被重復一次。因此可以匹配字符串 “aab”。
示例 5:
輸入:
s = “mississippi”
p = “mis*is*p*.”
輸出: false
一開始的思路,,,,好吧沒有思路
只能使用字符串中關于正則的匹配API,代碼如下
class Solution {
public boolean isMatch(String s, String p) {
return s.matches(p);
}
}
其實我們仔細考慮一下,無非就是分三種情況
假設主串為 A,模式串為 B , A 的長度為 n ,B 的長度為 m ,關注正則表達式 B 的最后一個字符是誰,它有三種可能,正常字符,* 和 .(點),那針對這三種情況討論即可,如下:
如果 B 的最后一個字符是正常字符,那就是看 A[n-1] 是否等于 B[m-1],相等則看 A_{0..n-2}與 B_{0..m-2},不等則是不能匹配,這就是子問題。
如果 B 的最后一個字符是 .(點) ,它能匹配任意字符,直接看 A_{0..n-2}與 B_{0..m-2}
如果 B 的最后一個字符是 * ,它代表 B[m-2]=c 可以重復0次或多次,它們是一個整體 c*
情況一:A[n-1]是 0個 c,B 最后兩個字符廢了,能否匹配取決A_{0..n-1}和 B_{0..m-3}是否匹配
情況二:A[n-1]是多個 c 中的最后一個(這種情況必須 A[n?1]=c 或者 c=’.’),所以 A 匹配完往前挪一個,B 繼續匹配,因為可以匹配多個,繼續看 A_{0..n-2}和 B_{0..m-1}是否匹配。
先來個某大神動態規劃的思路
轉移方程
f[i][j] 代表 A 的前 i 個和 B 的前 j 個能否匹配
對于前面兩個情況,可以合并成一種情況 f[i][j] = f[i-1][j-1]
對于第三種情況,對于 c* 分為看和不看兩種情況
不看:直接砍掉正則串的后面兩個, f[i][j] = f[i][j-2]
看:正則串不動,主串前移一個,f[i][j] = f[i-1][j]
特判:需要考慮空串空正則
空串和空正則是匹配的,f[0][0] = true
空串和非空正則,不能直接定義 true 和 false ,必須要計算出來。(比如A=” “ ,B=abc*)
非空串和空正則必不匹配,f[1][0]=…=f[n][0]=false
非空串和非空正則,那肯定是需要計算的了。
大體上可以分為空正則和非空正則兩種,空正則也是比較好處理的,對非空正則我們肯定需要計算,非空正則的三種情況,前面兩種可以合并到一起討論,第三種情況是單獨一種,那么也就是分為當前位置是 * 和不是 * 兩種情況了。
再來個遞歸代碼,遞歸代碼與上面的思路其實是一樣的
package ddx.september.day29;
public class Normal_19 {
public boolean isMatch(String s, String p) {
if (s.length() == 0 ) {
//主串為空
if (p.length() % 2 != 0) {
//模式串長度為奇數,則一定不匹配,因為抵消不了奇數
//例如:"." , "ab*","abc"
return false;
} else {
//長度為偶數,只需要判斷偶數位上是不是*即可!
int i = 1;
while (i < p.length()) {
if (p.charAt(i) != '*') {
return false;
}
i += 2;
}
return true;
}
} else if (p.length() == 0) {
//模式串為空
return false;
} else {
char ch1 = s.charAt(0); //s的首位
char ch2 = p.charAt(0); //p的首位
char ch3 = 'a'; //p的下一位
if(p.length() > 1){
ch3 = p.charAt(1);
}
//照樣分情況,看看是不是*
if(ch3 != '*'){
if(ch2 == ch1 || ch2 == '.'){
return isMatch(s.substring(1),p.substring(1));
}else{
//連正常字符和.都匹配不上
return false;
}
}else{
//難點就在于ch3是 *
//正常字符相等,或者是.
//即選擇或者不選擇!!!
//"aa"
//"a*a"
//上面兩個字符串,碰到*可以選擇,也可以不選擇
if(ch2 == ch1 || ch2 == '.'){
//前者是選擇,后者是不選擇
return isMatch(s.substring(1),p) || isMatch(s,p.substring(2));
}else{
//連正常字符和.都匹配不上,那么ch2 和 ch3廢了!!!!
return isMatch(s,p.substring(2));
}
}
}
}
}
本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
總結
以上是生活随笔為你收集整理的java 字符正则匹配算法_算法之字符串——正则表达式匹配的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何更改java源码_java – 如何
- 下一篇: java实现excel文件上传_java