你須要的LeeCode題No.07——「正則表達式匹配」_一點課堂(多岸學院)

正則表達式匹配

題目:正則表達式匹配java

描述:給定一個字符串 (s) 和一個字符模式 (p)。實現支持 '.' 和 '*' 的正則表達式匹配。正則表達式

  • '.' 匹配任意單個字符。
  • '*' 匹配零個或多個前面的元素。

匹配應該覆蓋整個字符串 (s) ,而不是部分字符串。數組

說明:函數

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

示例 1:學習

  • 輸入: s = "aa", p = "a"
  • 輸出: false
  • 解釋: "a" 沒法匹配 "aa" 整個字符串。

示例 2:code

  • 輸入: s = "aa", p = "a*"
  • 輸出: true
  • 解釋: '*' 表明可匹配零個或多個前面的元素, 便可以匹配 'a' 。所以, 重複 'a' 一次, 字符串可變爲 "aa"。

示例 3:blog

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

示例 4:遞歸

  • 輸入: s = "aab", p = "c*a*b"
  • 輸出: true
  • 解釋: 'c' 能夠不被重複, 'a' 能夠被重複一次。所以能夠匹配字符串 "aab"。

示例 5:圖片

  • 輸入: s = "mississippi", p = "mis*is*p*."
  • 輸出: false

解析

這應該是遇到的第一個困難類型的題目了。若是隻有 '.' 這個字符,匹配是十分簡單的,每匹配一個字符,問題就轉化爲在剩餘的字符串中作相同的操做,例如對於字符串 s="aa", p=".a" 而言,由於第一個字符 'a' 和 '.' 相匹配,因此問題就轉化成 s="a", p= "a" 是否匹配。若是咱們用函數 f(x, y) 表示字符串 s 的 前 x 位與字符串 p 的前 y 位是否匹配,那麼它具備如下的表達式:ip

若是 s.charAt(x)能夠匹配p.charAt(y),則 f(x, y) = f(x+1, y+1)
不然,f(x, y) = false

然而,由於 '*' 定義爲能夠匹配零個或多個前面的元素,這使得上述規則再也不適用,因此咱們要對它進行適當的修正。首先,'*' 必須在某個小寫字母或者 '.' 以後,這就意味着咱們必須校驗一個字符後邊是否有 '*' 標記,若是有,字符串 s 能夠與這部分不匹配,例如 s="aa", p="b*aa",雖然第一個字符 'a' 不能匹配 'b',但因爲 '*' 的緣由,能夠忽略這部分不一樣。因此咱們有了以下策略:

記 canMatchFirst表示s.charAt(x)是否能夠匹配p.charAt(y)
若是p.charAt(y+1)=='\*',f(x, y) = f(x, y+2) || (canMatchFirst && f(x+1, y))
不然和只有 '.' 時同樣,f(x, y) = canMatchFirst && f(x+1, y+1)

有了思路,咱們就能夠寫代碼了,參考以下:

public boolean isMatch(String s, String p) {
    return isMatch(s, p, s.length(), p.length(), 0, 0);
}
private boolean isMatch(String s, String p, int lenOfS, int lenOfP, int startS, int startP) {
    // 當前參與遞歸運算的長度
    int currLenOfS = lenOfS - startS;
    int currLenOfP = lenOfP - startP;

    if (currLenOfP == 0) {
        return currLenOfS == 0;
    }

    char pc = p.charAt(startP);
    // 第一個字符是否匹配
    boolean canMatchFirst = currLenOfS != 0 && (pc == '.' || s.charAt(startS) == pc);

    // 第二個字符是 * 的狀況
    if (currLenOfP > 1 && p.charAt(startP + 1) == '*') {
        return isMatch(s, p, lenOfS, lenOfP, startS, startP + 2)
                || (canMatchFirst) && isMatch(s, p, lenOfS, lenOfP, startS + 1, startP);
    } else {
        return (canMatchFirst) && isMatch(s, p, lenOfS, lenOfP, startS + 1, startP + 1);
    }
}

總結

雖然咱們常常使用正則表達式,可是它的實現確實是十分複雜的,以上只能當作一個引子,展現了正則表達式最簡單的幾個狀況,可是它卻爲咱們瞭解正則表達式的實現提供了思路。以上的分析思路也十分重要,在以後的不少問題中,咱們都須要這樣思考。好了,接下來讓咱們看一個有趣的題目吧。

下題預告

題目:盛最多水的容器

描述:給定 n 個非負整數 a1,a2,...,an,每一個數表明座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別爲 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器能夠容納最多的水。

說明:你不能傾斜容器,且 n 的值至少爲 2。

file 圖中垂直線表明輸入數組 [1,8,6,2,5,4,8,3,7]。在此狀況下,容器可以容納水(表示爲藍色部分)的最大值爲 49。</div>

示例:

* 輸入: [1,8,6,2,5,4,8,3,7]
* 輸出: 49

相關源碼請加QQ獲取。


【感謝您能看完,若是可以幫到您,麻煩點個贊~】

更多經驗技術歡迎前來共同窗習交流: 一點課堂-爲夢想而奮鬥的在線學習平臺 http://www.yidiankt.com/

![關注公衆號,回覆「1」免費領取-【java核心知識點】] file

QQ討論羣:616683098

QQ:3184402434

想要深刻學習的同窗們能夠加我QQ一塊兒學習討論~還有全套資源分享,經驗探討,等你哦! 在這裏插入圖片描述

相關文章
相關標籤/搜索