補上週缺失的LeetCode;
題目:
給你一個字符串 s 和一個字符規律 p,請你來實現一個支持 ‘.’ 和 ‘*’ 的正則表達式匹配。
‘.’ 匹配任意單個字符
‘*’ 匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋 整個 字符串 s的,而不是部分字符串。
說明:
s 可能爲空,且只包含從 a-z 的小寫字母。
p 可能爲空,且只包含從 a-z 的小寫字母,以及字符 . 和 *。
來源:力扣(LeetCode)
解題思路:
way一:回溯法
用Pattern和s進行匹配時,Pattern有幾種情況:
cond1:pattern中沒“*”號,則pattern[i] in {text[i],"."},則說明匹配;
cond2:pattern中有“*”號:
在cond2中,pattern和s的模式匹配形式有如下幾種:
first = pattern[i] in {text[i],"."} and i<len(text)
if i+1 <= len(pattern)-1 and pattern[i+1] == “*”:
return isMatch(s[i],pattern[i+2]) or (first and isMatch(s[i+1],pattern[i])
else:
return isMatch(s[i+1],pattern[i+1])
上述的幾種情況,有以下幾種遞歸形式:dp(i,j) :
dp(i+1,j) #1
dp(i,j+2) #2
dp(i+1,j+1) #3
可以看出,如果我們現在想去dp(i+2,j+2),則可通過以下幾種路徑來實現:
dp(i,j) -> #3 -> #3 -> dp(i+2,j+2)
dp(i,j) -> #1 -> #1 -> #2 -> dp(i+2,j+2)
由此可知,在上述遞歸算法中,存在着 無數條 重疊子問題,因此,我們可以用 “動態規劃”的方法對其進行優化。
這裏 所謂“動態規劃”,其實就是在“遞歸”的基礎上,加了一個“備忘錄”,來記住 各個子問題的 value;
先給出 “遞歸算法” 的code,在 “way二”中,給出“動態規劃”的code;
//Java
class Solution{
public boolean isMatch(String s,String p){
if(pattern.isEmpty()):return s.isEmpty();
first = (!s.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == "."));
if(p.length()>=2 && p.charAt(1)=="*"){
return isMatch(s.substring(0),p.substring(2)) || (first && isMatch(s.substring(1),p))
else:
return (first && isMatch(s.substring(1),p.substring(1)))
}
}
way二:動態規劃法
動態規劃法 是在 遞歸算法的基礎上,加了一個備忘錄,記錄已經處理過的子問題,從而 防止程序進行重複計算。其code如下:
//java
class Solution{
public boolean isMatch(String s,String p){
boolean[][] dp = new boolean[s.length()+1][p.length()+1]; //這裏之所以用 p.length+1,是爲了防止 p.substring(j+2)時溢出;
return dp(0,0,s,p);
}
public boolean dp(int i,int j,String s,String p){
boolean ans;
if(dp[i][j] != null){
return dp[i][j];
} //使用備忘錄中記錄的值,避免 子問題的重複計算;
if(j == p.length()){
ans = i == s.length();
} // i,j都超出了 數組index,這種情況發生在P中有 星號 的時候
else{
first = (i < s.length() && (p.charAt(j) == s.charAt(i) || p.charAt(j) == "."));
if(j<= p.length()-2 && p.charAt(j+1) == "*"){
ans = (dp(i,j+2,s,p) || (first && dp(i+1,j,s,p)));
} //要麼 *代表0次,要麼*代表1次
else{
ans = (first && dp(i+1,j+1,s,p));
}
}
dp[i][j] = ans;
return ans;
}
}
總結:
我覺得最讚的一點是,巧妙的利用dp(i+1,j,s,p)的方式來實現 * 的無限循環;
看過一部電影,聽過一句話:
“這世上壞人之所以猖獗,是因爲好人的無所作爲” ;
喜歡 唐晶,胸懷正念,也能比賤鬥恨;
今天推薦一首歌《聽風無涯》:
…
是誰信筆描繪水墨江山
蒼青色依舊深沉如海
往事終於繚亂成繁華斑斕
望不穿他眼中流年荏苒
輕聲在夢中
喚無涯成滄海
像楓色飄零
轉眼情波成潭
漸漸消失漸漸消失
將回憶點燃
留下殘骸不在看
…
在也回不去的年少時光
在也不想見的人
後悔遇見