日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode精讲题 10正则表达式匹配(动态规划)

發(fā)布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode精讲题 10正则表达式匹配(动态规划) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

標(biāo)題

    • 題目描述
    • 遞歸(超時)
    • 動態(tài)規(guī)劃
    • 結(jié)語

題目描述

先點贊再觀看、帥哥靚女養(yǎng)成好習(xí)慣

10 正則表達式匹配

給你一個字符串 s 和一個字符規(guī)律 p,請你來實現(xiàn)一個支持 ‘.’ 和'*'的正則表達式匹配。
'.'匹配任意單個字符
'*'匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋 整個 字符串 s的,而不是部分字符串。

說明:

s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字符 . 和 *。

示例 1:

輸入:
s = “aa”
p = "a"
輸出: false
解釋: “a” 無法匹配 “aa” 整個字符串。

示例 2:

輸入:
s = “aa”
p = "a*"
輸出: true
解釋: 因為 ‘*’ 代表可以匹配零個或多個前面的那一個元素, 在這里前面的元素就是 ‘a(chǎn)’。因此,字符串 “aa” 可被視為 ‘a(chǎn)’ 重復(fù)了一次。

示例 3:

輸入:
s = "ab"
p = ".*"
輸出: true
解釋: ".*" 表示可匹配零個或多個('*')任意字符('.')。

示例 4:

輸入:
s = “aab”
p = “cab”
輸出: true
解釋: 因為 ‘*’ 表示零個或多個,這里 ‘c’ 為 0 個, ‘a(chǎn)’ 被重復(fù)一次。因此可以匹配字符串 “aab”。

示例 5:

輸入:
s = “mississippi”
p = "mis*is*p*."
輸出: false

遞歸(超時)

這題剛開始見到,還以為遇到原題了,因為跟劍指offer的其中一題非常像,劍指offer第52題正則表達式,只不過那題給的兩個char類型的數(shù)組,當(dāng)時弱弱的用遞歸暴力過了。

然后一頓操作把上次遞歸的方法重寫過來,結(jié)果超時了……
但是還是把這種遞歸的思路講一下,遞歸主要進行匹配所有情況,主要是看當(dāng)前位置兩個串串能不能匹配。

需要考慮*情況可以匹配,因為*可以出現(xiàn)0次,1次多次。那么在遇到使用*的如果匹配了,可以通過遞歸實現(xiàn)下面三者方式

  • 它可以使用0次(相當(dāng)于跟字符串下一部分匹配 a*aa和aa這個第一個a*可以看成0次)
  • 也可以使用1次(在當(dāng)前往后移例如a*aa和aaa轉(zhuǎn)成aa和aa的匹配)
  • 也可以使用多次(例如a*和aaa轉(zhuǎn)成a*和aa的匹配)

同樣,如果遇到*不可以匹配,那么就使用0次就行了(b*aa和aa匹配轉(zhuǎn)換成aa和aa匹配)

如果下一個不是*,那就考慮是否相當(dāng)或者模式字符是否為.進行繼續(xù)匹配或者終止就可以,在考慮一些開始結(jié)束情況就可以了,一個大概的思維導(dǎo)圖可以看一下。

這部分實現(xiàn)的代碼如下:

public static boolean isMatch2(String s, String p) {//System.out.println(s+" "+p);if (p.length() == 0)// 模式串為false{if (s.length() == 0)return true;return false;} else if (s.length() == 0) {// 匹配串為0if (p.length() % 2 == 1)return false;else {for (int i = 1; i < p.length(); i += 2) {if (p.charAt(i) != '*')return false;}return true;}} else if (p.length() == 1) {//匹配串長度為1if((s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')&&s.length()==1)//可以匹配return true;else {return false;}} else {// 兩個串串正常長度if(p.charAt(1)=='*')//下一個為*{if(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')//可以匹配 分別用0次 用若1次 用若干次{return isMatch(s.substring(1), p)||isMatch(s.substring(1), p.substring(2))||isMatch(s, p.substring(2));}else {//不匹配只能用0次return isMatch(s, p.substring(2));} }else {if(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')return isMatch(s.substring(1), p.substring(1));else {//完全失敗return false;}}}

很遺憾的超時了,不過在劍指offer是可以過的,主要遇到這種字符就會很麻煩:

isMatch("aaaaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*c")

因為這里面匹配中的a*任意一個都可以使用若干次導(dǎo)致遞歸種類太多爆棧。嚶嚶嚶。

動態(tài)規(guī)劃

這題正確而大眾的解法當(dāng)然是動態(tài)規(guī)劃了,我們知道動態(tài)規(guī)劃重在動態(tài)的規(guī)劃方程。并且當(dāng)前結(jié)果是基于父結(jié)果的。這題剛好就可以使用動態(tài)規(guī)劃來解答。

我們使用我們聲明一個dp[][]=new boolean[匹配串長度+1][模式串長度+1] 的二位數(shù)組用來儲存結(jié)果, 其中dp[i][j]表示匹配串前i個和模式串前j個是否匹配。最終匹配串和模式串是否匹配就是返回dp[匹配串長度][模式串長度].

對于動態(tài)規(guī)劃的問題,我們一般會空余出0號位放在越界等特殊情況,所以我們聲明的二維數(shù)組大小長寬都大1,因為0號在dp[][]表示的是空串的結(jié)果而不是一號位置串的結(jié)果。然后我們在搞動態(tài)規(guī)劃題一般需要以下幾步:

  • 聲明dp數(shù)組,理解其含義
  • 聲明一些初始情況(一般為0)
  • 找正常情況動態(tài)方程式

這里的初始我們是dp[0][0]=true表示兩個空串可以匹配。

我們分析這個dp[i][j] 匹配串前i個,模式串前j個是否匹配.其實這個分析和之前遞歸還是有點相似的:

首先如果模式串pattern第j個如果是*,以下兩種情況任意一種匹配成功即可。

  • 如果dp[i][j-2]==true那么dp[i][j]肯定為true,因為可以把它看成一個空串。

  • 如果dp[i][j-2]不為true也不要緊,如果匹配串和模式串前一個字符可以匹配并且dp[i-1][j]為true,那么也可以匹配(a*和a )

如果模式串第j個不為*那么就是常規(guī)匹配了,如果當(dāng)前位置字符不匹配,那么就為false,如果當(dāng)前位置匹配且dp[i-1][j-1]==true那么dp[i][j]就為true:

當(dāng)然,以上所有考慮i-1的情況i不能等于0.

綜上分析得到dp方程為:

if(模式串當(dāng)前為*) dp[i][j]==dp[i][j-2]||(dp[i-1][j]&&兩串當(dāng)前字符可以匹配) else dp[i][j]=dp[i-1][j-1]&&兩串當(dāng)前字符可以匹配

具體實現(xiàn)需要注意下標(biāo)編號在字符串位置和dp下標(biāo)的含義,具體實現(xiàn)的代碼為:

public static boolean isMatch(String s, String p) {boolean dp[][]=new boolean[s.length()+1][p.length()+1];//默認(rèn)為falsedp[0][0]=true;for(int i=0;i<=s.length();i++){for(int j=1;j<=p.length();j++){if(p.charAt(j-1)=='*')//該位置為*{dp[i][j]=dp[i][j-2];//模式用了0次的看看是否能夠匹配,能匹配最好,不能匹配繼續(xù)if(!dp[i][j])//不能匹配{if(i==0) {continue;}else if(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)=='.')//可以匹配{dp[i][j]=dp[i-1][j];}}}else {//正常字符if(i==0){continue;}else if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.') {//這個位置可以匹配dp[i][j]=dp[i-1][j-1];}} }}return dp[s.length()][p.length()]; }

結(jié)語

今天又get一個動態(tài)規(guī)劃題,以前沒有用動態(tài)規(guī)劃的思維去想過,但是這題還是挺好的,至于一些其他的方法如果后面有時間可以繼續(xù)拓展。

原創(chuàng)不易,最后我請你幫兩件事幫忙一下:

  • star支持一下, 您的肯定是我在平臺創(chuàng)作的源源動力。

  • 微信搜索「bigsai」,關(guān)注我的公眾號,不僅免費送你電子書,我還會第一時間在公眾號分享知識技術(shù)。加我還可拉你進力扣打卡群一起打卡LeetCode。

  • 記得關(guān)注、咱們下次再見!

    《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的LeetCode精讲题 10正则表达式匹配(动态规划)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。