LeetCode第10題 正規表示式

2021-10-11 01:29:24 字數 3919 閱讀 1710

給你乙個字串 s 和乙個字元規律 p,請你來實現乙個支援 『.』 和 『*』 的正規表示式匹配。

『.』 匹配任意單個字元

『*』 匹配零個或多個前面的那乙個元素

所謂匹配,是要涵蓋整個字串 s 的,而

是部分字串。

輸入:s = 「aa」 p = 「a」

輸出:false

解釋:「a」 無法匹配 「aa」 整個字串。

輸入:s = 「aa」 p = 「a*」

輸出:true

解釋:因為 『*』 代表可以匹配零個或多個前面的那乙個元素, 在這裡前面的元素就是 『a』。因此,字串 「aa」 可被視為 『a』 重複了一次。

輸入:s = 「ab」 p = 「."

輸出:true

解釋:".」 表示可匹配零個或多個(』*』)任意字元(』.』)。

輸入:s = 「aab」 p = 「cab」

輸出:true

解釋:因為 『*』 表示零個或多個,這裡 『c』 為 0 個, 『a』 被重複一次。因此可以匹配字串 「aab」。

輸入:s = 「mississippi」 p = 「misisp*.」

輸出:false

0 <= s.length <= 20

0 <= p.length <= 30

s 可能為空,且只包含從 a-z 的小寫字母。

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

保證每次出現字元 * 時,前面都匹配到有效的字元

第一眼看上去該題要使用動態規劃,接下來將分析具體的思路。

首先我們先建立乙個 dp[m + 1][n + 1] 陣列,dp[i][j]表示s[0:i]和p[0:j]是否能夠匹配,m、n分別是字串s和p的長度,之所以要+1是因為要給陣列乙個初始的值,即兩個空串肯定是可以匹配的,dp[0][0] = true.

題目的要求就是兩個字串能夠以一定的規則匹配,其中 s 字串全是英文本元,p字串含有英文本元和兩個符號:『 . 』和『 * 』。

那麼我們可以根據p中字元的種類將整個思路分成三種情況:

p[j] 為普通英文本元

p[j] 為『.

p[j] 為『 * 』

這種是最一般的情況,假設此時 s 字串走到了 i 位置,p 字串走到了 j 位置,如下圖:

在上圖示例中,s[0:i] 和 p[0:j]能夠匹配成功有兩個條件:首先必須滿足s[0: i-1]和p[0: j-1]是可以匹配成功的,其次要滿足s[i]和p[j]是匹配成功的。

由此可以得出:

dp[i][j] = dp[i - 1][j - 1] && s[i] == p[j]

這種情況其實是上一種情況的特殊版,原因在於:』.『可以匹配任意乙個普通英文本元,兩個重點:「 任意 」 和 「 乙個 」,也就是說,當p[j]為』.『時,無論s[i]為什麼,在題目的規則下,永遠滿足s[i] == p[j]。示例如下:

根據規則,上圖中滿足:』 b 』 == 『.

由此可以得出:

dp[i][j] = dp[i-1][j-1]

這種情況其實是最複雜的情況,』 * '可以代表非負數個前乙個字元,我們並不知道代表多少個,這就是這種情況的複雜之處。·

我們先看上圖的例子:根據肉眼觀察,這時候,『 * 』代表0個前乙個字元,相當於「 a* 」這樣乙個整體相當於乙個""字串,即空字串,相當於把「 a* 」在p字串中消失了。

那麼什麼時候我們要考慮』 * '代表0個前乙個字元呢?

很顯然,如果s[i] 與 p[j-1] 不相等,那麼就說明當前位置下,』 * 『代表0個前乙個字元。即:

s[i] != p[j-1] => dp[i][j] == dp[i][j-2]

那麼s[i] == p[j]的時候,就要考慮』 * 『代表非0個前乙個字元的情況了,我們先看乙個極端的例子:

這裡的 』 * 』 代表多個』 e ',由於我們不知道具體代表多少個,那麼這裡我們就假設代表1個,假設的結果是什麼呢?

對,讓 i 左移乙個單位,那麼

dp[i][j] = dp[i - 1][j]。

左移之後,會再次遇到這種情況,從而再次左移,最後會出現下面的情況:

這種情況是不是似曾相識?

對,這種情況屬於』 * '代表 0 個前乙個字母的情況,正好就是我們之前講過的s[i] != p[j-1]這種情況。此時:

dp[i][j] = dp[i][j-2]

也就是說,無論』 * 『表示多少個前乙個字母的情況,最後都會回到代表0個的情況。

綜上所述,

p[j]是普通字元,則:

dp[i][j] = dp[i-1][j-1] && s[i]==p[j]

p[j]是』 . 『,則:

dp[i][j] = dp[i-1][j-1]

p[j]是』 * ',則:

if s[i] == p[j-1]

dp[i][j] = dp[i][j-2] or dp[i-1][j]

if s[i] != p[j-1]

dp[i][j] = dp[i][j-2]

可以寫出下列的狀態轉移方程:

d p[

i][j

]=if(p[j] ≠ '*') = \begin dp[i-1][j-1], & \text\\ false, &\text\\ \end\\ otherwise = \begin dp[i-1][j] or dp[i][j-2], & \text\\ dp[i][j-2], & \text \end \end

dp[i][

j]=⎩

⎪⎪⎪⎪

⎨⎪⎪⎪

⎪⎧​i

f(p[

j]​

=′∗′

)=}else}}

}return dp[m]

[n];

}public

boolean

ismatch

(string s, string p,

int i,

int j)

if( p.

charat

(j-1)==

'.')

return s.

charat

(i-1

)== p.

charat

(j-1);

}}

LeetCode第141題 環形鍊錶

給定乙個鍊錶,判斷鍊錶中是否有環。為了表示給定鍊錶中的環,我們使用整數 pos 來表示鍊錶尾連線到鍊錶中的位置 索引從 0 開始 如果 pos 是 1,則在該鍊錶中沒有環。示例 1 輸入 head 3,2,0,4 pos 1 輸出 true 解釋 鍊錶中有乙個環,其尾部連線到第二個節點。defini...

LeetCode第141題環形鍊錶

題目描述 給定乙個鍊錶,判斷鍊錶中是否有環。為了表示給定鍊錶中的環,我們使用整數 pos 來表示鍊錶尾連線到鍊錶中的位置 索引從 0 開始 如果 pos 是 1,則在該鍊錶中沒有環。解題思路 1 初步想法 沒有想法,估計是沒怎麼接觸鍊錶的題,看到別人的 用了兩個變數,乙個變數走一步,乙個變數走兩步,...

Leetcode第141題 環形鍊錶

給定乙個鍊錶,判斷鍊錶中是否有環。如果鍊錶中存在環,則返回 true 否則,返回 false 示例 1 輸入 head 3,2,0,4 pos 1 輸出 true 解釋 鍊錶中有乙個環,其尾部連線到第二個節點。示例 2 輸入 head 1,2 pos 0 輸出 true 解釋 鍊錶中有乙個環,其尾部...