精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
動態規劃之正則表達式

之前的文章 動態規劃詳解 收到了普遍的好評,今天寫一個動態規劃的經典應用:正則表達式。如果有讀者對「動態規劃」還不了解,建議先看一下上面那篇文章。

正則表達式匹配是一個很精妙的算法,而且難度也不小。本文主要寫兩個正則符號的算法實現:點號「.」和星號「*」,如果你用過正則表達式,應該明白他們的用法,不明白也沒關系,等會會介紹。文章的最后,還會介紹一種快速看出重疊子問題的技巧。

本文還有一個重要目的,就是教會讀者如何設計算法。我們平時看別人的解法,直接看到一個面面俱到的完整答案,總覺得無法理解,以至覺得問題太難,自己太菜。我力求向讀者展示,算法的設計是一個螺旋上升、逐步求精的過程,絕不是一步到位就能寫出正確算法的。本文會帶你解決這個較為復雜的問題,讓你明白如何化繁為簡,逐個擊破,從最簡單的框架搭建出最終的答案。

前文無數次強調的框架思維,就是在這種設計過程中逐步培養的。下面進入正題,首先看一下題目:

一、熱身

第一步,我們暫時不管正則符號,如果是兩個普通的字符串進行比較,如何進行匹配?我想這個算法應該誰都會寫:

然后,我稍微改造一下上面的代碼,略微復雜了一點,但意思還是一樣的,很容易理解吧:

如上改寫,便于理解如何將這個算法改造成遞歸算法(偽碼):

如果你能夠理解這段代碼,恭喜你,你的遞歸思想已經到位,而且正則表達式問題已經解決了一半。

二、處理點號「.」通配符

點號可以匹配任意一個字符,萬金油嘛,其實是最簡單的。將上述偽碼改成 python 代碼,再稍加改造即可:

三、處理星號「*」通配符

星號通配符可以讓前一個字符出現任意次數,包括零次。那到底是出現幾次呢?這似乎有點困難,不過不要著急,我們起碼可以把框架的搭建再進一步:

星號前面的那個字符到底要出現幾次呢?這需要計算機暴力窮舉的,假設出現 N 次吧。前文多次強調過,寫遞歸的技巧是管好當下,之后的事拋給遞歸。具體到這里,不管 N 是多少,當前的選擇只有兩個:出現 0 次、出現 1 次。所以可以這樣處理:

配合一個圖示就能理解這個邏輯了。假設 pattern = 'a*', text = 'aa',畫個圖:

可以看到,我們是通過保留 pattern 中的「*」,同時向后推移 text,來實現「*」讓字符出現多次的功能。

至此,正則表達式算法就完成了,這個問題根本沒有看起來那么困難,對吧?現在只需要用下備忘錄或者

DP table 消除「重疊子問題」,降低一下復雜度就行了。

四、動態規劃

我選擇使用「備忘錄」遞歸的方法來降低復雜度。有了暴力解法,優化的過程及其簡單,就是使用兩個變量 i, j 記錄當前匹配到的位置,從而避免使用子字符串切片,并且將 i, j 存入備忘錄,避免重復計算即可。

我將暴力解法和優化解法放在一起,方便你對比,你可以發現優化解法無非就是把暴力解法「翻譯」了一遍,加了個 memo 作為備忘錄,僅此而已。

有的讀者也許會問,你怎么知道這個問題是個動態規劃問題呢,你怎么知道它就存在「重疊子問題」呢?這似乎不容易看出來呀。

解答這個問題,最直觀的應該是隨便假設一個輸入,然后畫遞歸樹,肯定是可以發現相同節點的。這屬于定量分析,其實不用這么麻煩,下面教你定性分析,一眼就能看出「重疊子問題」性質。

先拿最簡單的斐波那契數列舉例,我們抽象出遞歸算法的框架:

def fib(n):
fib(n - 1) #1
fib(n - 2) #2

看著這個框架,請問原問題 f(n) 如何觸達子問題 f(n - 2) ?有兩種路徑,一是 f(n) -> #1 -> #1, 二是 f(n) -> #2。前者經過兩次遞歸,后者經過一次遞歸而已。兩條不同的計算路徑都到達了同一個問題,這就是「重疊子問題」,而且可以肯定的是,只要你發現一條重復路徑,這樣的重復路徑一定存在千萬條,意味著巨量子問題重疊。

同理,對于本問題,我們依然先抽出算法框架:

def dp(i, j):
dp(i, j + 2) #1
dp(i + 1, j) #2
dp(i + 1, j + 1) #3

提出類似的問題,請問如何從原問題 dp(i, j) 觸達子問題 dp(i + 2, j + 2) ?至少有兩種路徑,一是 dp(i, j) -> #3 -> #3,二是 dp(i, j) -> #1 -> #2 -> #2。因此,本問題一定存在重疊子問題,一定需要動態規劃的優化技巧來處理。

五、最后總結

通過本文,你深入理解了正則表達式的兩種常用通配符的算法實現。其實點號「.」的實現及其簡單,關鍵是星號「*」的實現需要用到動態規劃技巧,稍微復雜些,但是也架不住我們對問題的層層拆解,逐個擊破。另外,你掌握了一種快速分析「重疊子問題」性質的技巧,可以快速判斷一個問題是否可以使用動態規劃套路解決。

回顧整個解題過程,你應該能夠體會到算法設計的流程:從簡單的類似問題入手,給基本的框架逐漸組裝新的邏輯,最終成為一個比較復雜、精巧的算法。

所以說,讀者不必畏懼一些比較復雜的算法問題,稍加思考和類比,很多看似高大上的算法在你眼里也不過一個脆皮,不堪一擊。

本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
詳解一道騰訊面試題:編輯距離
動態規劃詳解
Python|動態規劃問題--斐波那契數列
力扣初級算法(六)【動態規劃】
詳解最長公共子序列問題,秒殺三道動態規劃題目
刻意練習:LeetCode實戰 -- Task30.通配符匹配
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 南宁市| 满洲里市| 梧州市| 诸暨市| 调兵山市| 扎囊县| 阳春市| 龙州县| 平陆县| 八宿县| 建宁县| 伊通| 色达县| 滁州市| 新宾| 桐柏县| 岗巴县| 洮南市| 平江县| 海原县| 庐江县| 北碚区| 香港 | 蓬莱市| 乌海市| 滨州市| 伊吾县| 河西区| 海门市| 卢氏县| 万盛区| 双牌县| 梓潼县| 宜川县| 山东省| 西安市| 酉阳| 哈巴河县| 海伦市| 威海市| 长汀县|