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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

力扣- -正则表达式匹配

發布時間:2024/4/11 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 力扣- -正则表达式匹配 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

力扣- -正則表達式匹配

文章目錄

  • 力扣- -正則表達式匹配
    • 一、題目描述
    • 二、分析
      • 方法一:Dp函數
        • 明確狀態和選擇
        • 確定狀態轉譯方程
        • 確定base case
        • 完整代碼
      • 方法二:Dp table
        • 明確狀態和選擇
        • 明確狀態轉移方程
        • 確定base case
        • 完整代碼

一、題目描述



二、分析

  • 這兩個通配符是最常用的,其中點號「.」可以匹配任意一個字符,星號「*」可以讓之前的那個字符重復任意次數(包括 0 次)。

  • 比如說模式串".a * b"就可以匹配文本"zaaab",也可以匹配"cb";模式串"a..b"可以匹配文本"amnb";而模式串".*"就比較牛逼了,它可以匹配任何文本。

  • 題目會給我們輸入兩個字符串s和p,s代表文本,p代表模式串,請你判斷模式串p是否可以匹配文本s。

  • 我們可以假設模式串只包含小寫字母和上述兩種通配符且一定合法,不會出現*a或者b**這種不合法的模式串,

  • 函數簽名如下:

bool isMatch(string s, string p);
  • 對于我們將要實現的這個正則表達式,難點在那里呢?

  • 點號通配符其實很好實現,s中的任何字符,只要遇到.通配符,無腦匹配就完事了。

  • 主要是這個星號通配符不好實現,一旦遇到*通配符,前面的那個字符可以選擇重復一次,可以重復多次,也可以一次都不出現,這該怎么辦?

  • 對于這個問題,答案很簡單,對于所有可能出現的情況,全部窮舉一遍,只要有一種情況可以完成匹配,就認為p可以匹配s。那么一旦涉及兩個字符串的窮舉,我們就應該條件反射地想到動態規劃的技巧了。

方法一:Dp函數

  • 整個s和p相互匹配的過程大致是,兩個指針i, j分別在s和p上移動,如果最后兩個指針都能移動到字符串的末尾,那么久匹配成功,反之則匹配失敗。
  • 正則表達算法問題只需要把住一個基本點:看兩個字符是否匹配,一切邏輯圍繞匹配/不匹配兩種情況展開即可
  • 如果不考慮*通配符,面對兩個待匹配字符s[i]和p[j],我們唯一能做的就是看他倆是否匹配:
bool isMatch(string s, string p) {int i = 0, j = 0;while (i < s.size() && j < p.size()) {// 「.」通配符就是萬金油if (s[i] == p[j] || p[j] == '.') {// 匹配,接著匹配 s[i+1..] 和 p[j+1..]i++; j++;} else {// 不匹配return false;}}return i == j; }

那么考慮一下,如果加入*通配符,局面就會稍微復雜一些,不過只要分情況來分析,也不難理解。

因為【 * 】號影響的范圍是根據【 * 】號前面的情況來進行判斷匹配0次還是多次的,所以當p[j + 1]為*通配符時,我們分情況討論下

  • 如果匹配,即s[i] == p[j],那么有兩種情況:
  • p[j]有可能會匹配多個字符,比如s = "aaa", p = "a*",那么p[0]會通過*匹配 3 個字符"a"。
  • p[i]也有可能匹配 0 個字符,比如s = "aa", p = "a*aa",由于后面的字符可以匹配s,所以p[0]只能匹配 0 次。
  • 如果不匹配,即s[i] != p[j],只有一種情況:
  • p[j]只能匹配 0 次,然后看下一個字符是否能和s[i]匹配。比如說s = "aa", p = "b*aa",此時p[0]只能匹配 0 次。

綜上,可以把之前的代碼針對*通配符進行一下改造:

bool isMatch(string s, string p) {int i = 0, j = 0;while (i < s.size() && j < p.size()) {if (s[i] == p[j] || p[j] == '.') {// 匹配if (j < p.size() - 1 && p[j + 1] == '*') {// 有 * 通配符,可以匹配 0 次或多次} else {// 無 * 通配符,老老實實匹配 1 次i++; j++;}} else {// 不匹配if (j < p.size() - 1 && p[j + 1] == '*') {// 有 * 通配符,只能匹配 0 次} else {// 無 * 通配符,匹配無法進行下去了return false;}}}return i == j; }
  • 整體的思路已經很清晰了,但現在的問題是,遇到*通配符時,到底應該匹配 0 次還是匹配多次?多次是幾次?

你看,這就是一個做「選擇」的問題,要把所有可能的選擇都窮舉一遍才能得出結果。

明確狀態和選擇

  • 動態規劃算法的核心就是「狀態」和「選擇」,「狀態」無非就是i和j兩個指針的位置,「選擇」就是p[j]選擇匹配幾個字符

  • 根據「狀態」,我們可以定義一個dp函數:

bool dp(string& s, int i, string& p, int j);
  • dp函數的定義如下:

  • 若dp(s,i,p,j) = true,則表示s[i..]可以匹配p[j..];若dp(s,i,p,j) = false,則表示s[i..]無法匹配p[j..]。

  • 根據這個定義,我們想要的答案就是i = 0,j = 0時dp函數的結果,所以可以這樣使用這個dp函數:

bool isMatch(string s, string p) {// 指針 i,j 從索引 0 開始移動return dp(s, 0, p, 0);

確定狀態轉譯方程

  • 通配符匹配 0 次或多次
return dp(s, i, p, j + 2) || dp(s, i + 1, p, j);
  • 將j加 2,i不變,含義就是直接跳過p[j]和之后的通配符,即通配符匹配 0 次:

  • 將i加 1,j不變,含義就是p[j]匹配了s[i],但p[j]還可以繼續匹配,即通配符匹配多次的情況:

    兩種情況只要有一種可以完成匹配即可,所以對上面兩種情況求或運算

  • 常規匹配 1 次

return dp(s, i + 1, p, j + 1);
  • 由于這個條件分支是無*的常規匹配,那么如果s[i] == p[j],就是i和j分別加一:

  • 通配符匹配 0 次
return dp(s, i, p, j + 2);
  • 類似情況 ,將j加 2,i不變
  • 如果沒有*通配符,也無法匹配,那只能說明匹配失敗了:

確定base case

  • 一個 base case 是j == p.size()時,按照dp函數的定義,這意味著模式串p已經被匹配完了,那么應該看看文本串s匹配到哪里了,如果s也恰好被匹配完,則說明匹配成功:
if (j == p.size()) {return i == s.size(); }
  • 另一個 base case 是i == s.size()時,按照dp函數的定義,這種情況意味著文本串s已經全部被匹配了,那么是不是只要簡單地檢查一下p是否也匹配完就行了呢?
if (i == s.size()) {// 這樣行嗎?return j == p.size(); }
  • 這都是不正確的,此時并不能根據j是否等于p.size()來判斷是否完成匹配,只要p[j..]能夠匹配空串,就可以算完成匹配。比如說s = "a", p = "ab*c*",當i走到s末尾的時候,j并沒有走到p的末尾,但是p依然可以匹配s。

base case:

int m = s.size(), n = p.size();if (i == s.size()) {// 如果能匹配空串,一定是字符和 * 成對兒出現if ((n - j) % 2 == 1) {return false;}// 檢查是否為 x*y*z* 這種形式for (; j + 1 < p.size(); j += 2) {if (p[j + 1] != '*') {return false;}}return true; }

完整代碼

class Solution { public:/* 計算 p[j..] 是否匹配 s[i..] */bool dp(string& s, int i, string& p, int j) {int m = s.size(), n = p.size();if (i == s.size()) {// 如果能匹配空串,一定是字符和 * 成對兒出現if ((n - j) % 2 == 1) {return false;}// 檢查是否為 x*y*z* 這種形式for (; j + 1 < p.size(); j += 2) {if (p[j + 1] != '*') {return false;}}return true;}if (s[i] == p[j] || p[j] == '.') {// 匹配if (j < p.size() - 1 && p[j + 1] == '*') {// 通配符匹配 0 次或多次return dp(s, i, p, j + 2)|| dp(s, i + 1, p, j);} else {// 常規匹配 1 次return dp(s, i + 1, p, j + 1);}} else {// 不匹配if (j < p.size() - 1 && p[j + 1] == '*') {// 通配符匹配 0 次return dp(s, i, p, j + 2);} else {// 無法繼續匹配return false;}}}// 動態規劃bool isMatch(string s, string p) {return dp(s, 0, p, 0); } };

方法二:Dp table

Dp table的思想基本一致,只不過轉換為了數組而已

明確狀態和選擇

  • 動態規劃算法的核心就是「狀態」和「選擇」,「狀態」無非就是i和j兩個指針的位置,「選擇」就是p[j]選擇匹配幾個字符
  • dp[i][j] == true代表字符串s的[0.....i]和字符串p的[0.....j]是匹配的
  • dp[i][j] == false代表字符串s的[0.....i]和字符串p的[0.....j]是不匹配的

明確狀態轉移方程

  • p的前一個字符和s的前一個字符相等會p的前一個字符是'.'直接轉移
if(p[j - 1] == s[i - 1] || p[j - 1] == '.')dp[i][j] = dp[i - 1][j - 1];
  • 如果p的前一個為'*'就需要考慮匹配0次和多次了
if(p[j - 1] == '*') {bool zero, one;if(j - 2 >= 0){//匹配0次zero = dp[i][j - 2];//匹配多次one = (p[j - 2] == s[i - 1] || p[j - 2] == '.') && dp[i - 1][j];dp[i][j] = zero || one;} }

確定base case

dp[0][0] = true;for(int i = 1; i <= np; i++){if(i - 2 >= 0 && p[i - 1] == '*' && p[i - 2]){dp[0][i] = dp[0][i - 2];}}

完整代碼

class Solution { public:bool isMatch(string s, string p) {int ns = s.size();int np = p.size();if(p.empty()) return s.empty();vector<vector<bool>> dp(ns + 1, vector<bool>(np + 1, false));//初始化為true,因為空和空肯定是匹配的dp[0][0] = true;//這里的base case是初始化*匹配0次的情況for(int i = 1; i <= np; i++){if(i - 2 >= 0 && p[i - 1] == '*' && p[i - 2]){dp[0][i] = dp[0][i - 2];}}//開始狀態轉移for(int i = 1; i <= ns; i++){for(int j = 1; j <= np; j++){//p的前一個字符和s的前一個字符相等會p的前一個字符是'.'直接轉移if(p[j - 1] == s[i - 1] || p[j - 1] == '.')dp[i][j] = dp[i - 1][j - 1];//如果p的前一個為'*'就需要考慮匹配0次和多次了if(p[j - 1] == '*'){bool zero, one;if(j - 2 >= 0){//匹配0次zero = dp[i][j - 2];//匹配多次one = (p[j - 2] == s[i - 1] || p[j - 2] == '.') && dp[i - 1][j];dp[i][j] = zero || one;}}}}return dp[ns][np];} };

總結

以上是生活随笔為你收集整理的力扣- -正则表达式匹配的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 韩日三级视频 | 国产精华一区二区三区 | 舐丝袜脚视频丨vk | 国产精品19乱码一区二区三区 | 催眠调教艳妇成肉便小说 | 日日射夜夜操 | 极品少妇xxxx精品少妇偷拍 | 国产女人精品视频 | 一区二区三区在线免费视频 | 欧美日韩精品区别 | 天堂成人 | 精品成人av| 国产白袜脚足j棉袜在线观看 | 成人网免费视频 | 国产麻豆精品久久一二三 | 99精品免费在线观看 | 少妇视频网 | 成人精品一区二区三区中文字幕 | 欧美黄色片视频 | www.av在线视频 | 欧美xxxxxxxxx| 999精品在线视频 | 日韩欧美中文一区 | 日韩福利社 | 成人免费看片在线观看 | 嫩草嫩草嫩草嫩草嫩草嫩草 | 国产一区视频免费观看 | 久久成人福利 | 青青操视频在线 | 欧美不卡网 | 亚洲第一页在线 | 在线视频资源 | 又色又爽又黄无遮挡的免费视频 | 靠逼在线观看 | 卡通动漫亚洲综合 | 亚洲天堂一区二区三区四区 | 亚洲成年人免费观看 | 500部大龄熟乱视频 亚洲乱码精品 | 亚洲精品精品 | 免费日韩在线视频 | 玖玖在线免费视频 | 人妻体体内射精一区二区 | 最新av| 天天久久综合 | 亚洲男人天堂2020 | 色女孩综合 | 中文字幕av在线免费 | 国产精品黑人一区二区三区 | 对白刺激国产子与伦 | 天天噜日日噜 | 九九热视频在线 | 亚洲精品九九 | 亚洲天堂网在线视频 | 97精品一区二区三区 | 夜夜骑狠狠干 | 一本久久综合亚洲鲁鲁五月天 | 老熟妇午夜毛片一区二区三区 | 做暧暧视频在线观看 | 蜜桃av网站| 99re视频精品| 免费在线观看中文字幕 | 日本视频网站在线观看 | 欧美1区2区3区4区 | 绿帽视频| 欧美黄色特级视频 | 人妻内射一区二区在线视频 | 中文字幕第31页 | 欧美日色 | 精品少妇一区二区 | 欧美性激情 | 美梦视频大全在线观看高清 | 综合网亚洲 | 色婷婷六月天 | 亚洲一二三区在线 | a级在线免费观看 | 欧美一级视频免费 | 操欧美美女 | 亚洲成网站| 狠狠做| 中文婷婷 | 在线播放视频高清在线观看 | 亚洲色图网友自拍 | 天堂俺去俺来也www久久婷婷 | 成年人网站免费视频 | 欧美一区二区三区黄色 | 精品无码在线观看 | 伊人久久91 | 在线色网| 欧美日韩国产一区二区三区 | 97国产视频| 久热最新 | 国产精品毛片久久久 | 国产成人精品视频一区二区 | 欧美国产日韩在线视频 | 国产夫妻在线观看 | 国产a∨精品一区二区三区仙踪林 | 黄色日皮视频 | 久久亚洲色图 | 日韩欧美国产中文字幕 |