乘風破浪:LeetCode真題_010_Regular Expression Matching

乘風破浪:LeetCode真題_010_Regular Expression Matching

一、前言

? ? 關于正則表達式我們使用得非常多,但是如果讓我們自己寫一個,卻是有非常大的困難的,我們可能想到狀態機,確定,非確定狀態機確實是一種解決方法,不過需要消耗很大的時間去推理和計算,對于正則表達式的縮小版,我們往往可以通過遞歸,遞推,動態規劃等方法來解決。

二、Regular Expression Matching

2.1 問題理解

2.2 問題分析和解決

??? 遇到這樣的問題,我們想到了遞歸,對于.是很好處理和匹配的,但是如果和*結合起來就變化無窮了,正是因為*我們才要遞歸。

??? 讓我們看看官方的答案:

class Solution {public boolean isMatch(String text, String pattern) {if (pattern.isEmpty()) return text.isEmpty();boolean first_match = (!text.isEmpty() &&(pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));if (pattern.length() >= 2 && pattern.charAt(1) == '*'){return (isMatch(text, pattern.substring(2)) ||(first_match && isMatch(text.substring(1), pattern)));} else {return first_match && isMatch(text.substring(1), pattern.substring(1));}}
}

??? 如果模式串和源串第一個字符能夠正常匹配,并且不為空,模式串的第二個字符不為'*',那么我們可以繼續遞歸匹配下面的東西:

1 return first_match && isMatch(text.substring(1), pattern.substring(1));

??? 如果模式串的長度大于1,并且第二個字符是*,那么我們就有可能匹配到源串的很多的字符,也就相當于將源串已經匹配的去掉,拿剩下的和整個模式串繼續比較,此時*發揮了作用,或者比較源串與去掉了*的模式串,因為*沒有能夠發揮作用。于是就得到了:

1         if (pattern.length() >= 2 && pattern.charAt(1) == '*'){
2             return (isMatch(text, pattern.substring(2)) ||
3                     (first_match && isMatch(text.substring(1), pattern)));
4         } 

???? 除此之外我們還可以使用動態規劃算法:

class Solution {public boolean isMatch(String text, String pattern) {boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];dp[text.length()][pattern.length()] = true;for (int i = text.length(); i >= 0; i--){for (int j = pattern.length() - 1; j >= 0; j--){boolean first_match = (i < text.length() &&(pattern.charAt(j) == text.charAt(i) ||pattern.charAt(j) == '.'));if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];} else {dp[i][j] = first_match && dp[i+1][j+1];}}}return dp[0][0];}
}

???? 首先我們定義dp[i][j]代表源串T[i:]和模式串P[j:]是匹配的,其中i,j為源串和模式串的下標,于是我們只要求得dp[0][0]的值就可以了。我們已知的條件是:

 dp[text.length()][pattern.length()] = true;

???? 于是我們從后往前倒求最終的dp[0][0],通過如下的判斷,看看是哪一種情況,然后根據相應的情況采取不同的遞推策略,最終得到結果:

1    boolean first_match = (i < text.length() &&
2                             (pattern.charAt(j) == text.charAt(i) ||
3                             pattern.charAt(j) == '.'));
4    if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
5          dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
6    } else {
7          dp[i][j] = first_match && dp[i+1][j+1];
8    }

?????? 同樣的我們算法也是使用了遞歸和動態規劃:

??? 在動態規劃方面我們使用match[i]來表示對于源串從i到最后(T[i:])都是能夠匹配的,于是之用求match[0]即可。

import java.util.Arrays;public class Solution {/*** Implement regular expression matching with support for '.' and '*'.* '.' Matches any single character.* '*' Matches zero or more of the preceding element.** 題目大意:* 實現一個正則表達式匹配算法,.匹配任意一個字符,*匹配0個或者多個前導字符*/public boolean isMatch(String s, String p) {boolean[] match = new boolean[s.length() + 1]; Arrays.fill(match, false);match[s.length()] = true;//剛開始滿足需要for (int i = p.length() - 1; i >= 0; i--) {if (p.charAt(i) == '*') {for (int j = s.length() - 1; j >= 0; j--)  {
          //原來就是false只有能夠為真,才為真。match[j] = match[j] || match[j + 1]&& (p.charAt(i - 1) == '.' || s.charAt(j) == p.charAt(i - 1));}i--;} else {for (int j = 0; j < s.length(); j++) {
//從前往后,只有到了已經有true的時候才能生效。如果從后往前反而有問題。 match[j] = match[j + 1]&& (p.charAt(i) == '.' || p.charAt(i) == s.charAt(j));}//將最后的置為假,本來就應該不真,便于以后的判斷match[s.length()] = false;}}return match[0];}// 下面的代碼用時比較長public boolean isMatch2(String s, String p) {// 輸入都為nullif (s == null && p == null) {return true;}// 有一個為nullelse if (s == null || p == null) {return false;}return isMatch(s, 0, p, 0);}/*** 正則表達式匹配** @param s 匹配串* @param sIdx 當前匹配的位置* @param p 模式串* @param pIdx 模式串的匹配位置* @return 匹配結果*/public boolean isMatch(String s, int sIdx, String p, int pIdx) {// 同時到各自的末尾if (s.length() == sIdx && p.length() == pIdx) {return true;}// 當匹配串沒有到達末尾,模式串已經到了末尾else if (s.length() != sIdx && p.length() == pIdx) {return false;}// 其它情況else {// 如果當前匹配的下一個字符是*號if (pIdx < p.length() - 1 && p.charAt(pIdx + 1) == '*') {// 匹配串未結束并且當前字符匹配(字符相等或者是.號)if (sIdx < s.length() && (s.charAt(sIdx) == p.charAt(pIdx) || p.charAt(pIdx) == '.')) {return isMatch(s, sIdx + 1, p, pIdx + 2) // 匹配串向前移動一個字符(只匹配一次)|| isMatch(s, sIdx + 1, p, pIdx) // 匹配串向前移動一個字符(下一次匹配同樣的(模式串不動))|| isMatch(s, sIdx, p, pIdx + 2); // 忽略匹配的模式串} else {// 忽略*return isMatch(s, sIdx, p, pIdx + 2);}}// 匹配一個字符if (sIdx < s.length() && (s.charAt(sIdx) == p.charAt(pIdx) || p.charAt(pIdx) == '.')) {return isMatch(s, sIdx + 1, p, pIdx + 1);}}return false;}}

?

??? 如下表所示,使用遞歸需要1163ms而使用動態規劃需要20ms,差別非常顯著。

三、總結

???? 對于一些比較困難的問題,我們需要從不同的角度考慮,解決問題的方法可以從遞歸,遞推,動態規劃等方面去考慮。

轉載于:https://www.cnblogs.com/zyrblog/p/10211390.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249895.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249895.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249895.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python——獲取數據類型

在python中&#xff0c;可使用type()和isinstance()內置函數獲取數據類型 如&#xff1a; &#xff08;1&#xff09;type()的使用方法&#xff1a;    >>> a 230 >>> type(a) <class str> >>> a 230 …

vue項目工程中npm run dev 到底做了什么

npm install 安裝了webpack框架中package.json中所需要的依賴 2.安裝完成之后&#xff0c;需要啟動整個項目運行&#xff0c;npm run 其實執行了package.json中的script腳本&#xff0c;npm run dev的執行如下 3.底層相當執行webpack-dev-server --inline --progress --confi…

JavaScript回顧與學習——條件語句

一、if...else // if elsevar age 16;if(0 < age && age < 6){console.log("兒童");}else if(6 < age && age < 14){console.log("少年");}else if(14 < age && age < 35){console.log("青年");}els…

bat等大公司常考java多線程面試題

1、說說進程,線程,協程之間的區別 簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執行過程中擁有獨立的內存單元,而多個線程共享內存資源,減少切換次數,從而效率更高.線程是進程的一個實體,是cpu調度和分派的基本單位,是比…

webpack.config.js和package.json

webpack.config.js 是webpakc的配置文件&#xff0c;webpack是當今很火的一個打包工具 使用webpack.config.js在你的項目里 可以對你的項目進行模塊化打包&#xff0c;并且也可使組件按需加載&#xff0c;還可將圖片變成base64格式減少網絡請求。 而package.json 是指你項目的…

七牛云圖片加載優化

?imageView2/2/w/80https://developer.qiniu.com/dora/manual/1279/basic-processing-images-imageview2 ?imageView2/1/w/80/h/80會裁剪 ?imageView2/3/w/80/h/80不會裁剪 轉載于:https://www.cnblogs.com/smzd/p/9025393.html

org.apache.maven.archiver.mavenarchiver.getmanifest怎么解決

原因就是你的maven的配置文件不是最新的 1.help ->Install New Software -> add ->https://otto.takari.io/content/sites/m2e.extras/m2eclipse-mavenarchiver/0.17.2/N/LATEST 或者&#xff08;更新于2018年4月18日17:07:53&#xff09; http://repo1.maven.org/mav…

npm中package.json詳解

通常我們使用npm init命令來創建一個npm程序時&#xff0c;會自動生成一個package.json文件。package.json文件會描述這個NPM包的所有相關信息&#xff0c;包括作者、簡介、包依賴、構建等信息&#xff0c;格式是嚴格的JSON格式。 常用命令 npm i --save packageName 安裝依賴…

offset系列,client系列,scroll系列回顧

一 scroll系列屬性 ——滾動1 scrollHeight/scrollWidth 標簽內部實際內容的高度/寬度ele.scrollHeight 有兩種情況&#xff0c;當內容超出盒子范圍后&#xff0c;返回的是內容的高度&#xff0c;包括padding&#xff0c;從頂部內側到內容的最外部分。當內容不超出盒子范圍…

項目開發中的自我總結

最近忙的要死,因為新開發了兩個項目.現在已經測試完畢了,準備部署到線上了. 然后不能白忙活吧,忙活完也得寫點總結和經驗吧,以后也有個記錄. 1.一個bootstrapjquerylayuilaravel 5.4開發的一個后臺系統 比較樸素 2.一個前后端分離的vuelaravel 5.4 開發的商家系統 我只負責后端…

webpack.config.js 參數詳解

webpack.config.js文件通常放在項目的根目錄中&#xff0c;它本身也是一個標準的Commonjs規范的模塊。 var webpack require(webpack); module.exports {entry: [webpack/hot/only-dev-server,./js/app.js],output: {path: ./build,filename: bundle.js},module: {loaders: …

數組黑科技(偏性能方面)未完待更新...

數組去重最優解&#xff1a;Array.prototype.unique function () {var tmp new Map();return this.filter(item > {return !tmp.has(item) && tmp.set(item,1);})}搭配使用 Array.from(foo); // ["f", "o", "o"]let s new Set([f…

控制臺添加log4net

1.添加nuget包 log4net 2.app.config配置 <?xml version"1.0" encoding"utf-8"?> <configuration> <configSections><section name"log4net" type"log4net.Config.Log4NetConfigurationSectionHandler, log4net&quo…

記一次vue 普通異步請求微信二進制二維碼 亂碼 問題解決然后渲染

后端壓力大&#xff0c;前端分憂。 /*用微信小程序token拿二維碼*/ async fetchMINIQRcode({commit,state},params){var instance axios.create({responseType: blob, //返回數據的格式&#xff0c;可選值為arraybuffer,blob,document,json,text,stream&#xff0c;默認值為js…

vue-cli項目中.postcssrc.js

module.exports {"plugins": {"postcss-import": {}, //用于import導入css文件"postcss-url": {}, //路徑引入css文件或node_modules文件"postcss-aspect-ratio-mini": {}, //用來處理元素容器寬高比"postcss-…

本地存儲cookie和localStorage區別特點

一、cookie cookie算是比較早的技術&#xff0c;最初是為了記錄http的狀態&#xff0c;提高訪問速度。cookie是服務器"種植"在客戶端的key-value形式文本文件。但同時客戶端也能操作cookie。特點&#xff1a; 大小&#xff1a;cookie的大小限制在4k。每個域名下cooki…

VUE 中 使用 iview Form組件 enter鍵防止頁面刷新

<Form :label-width"100" inline label-positionleft keydown.native.enter.prevent "()>{}">或者使用官方的 submit.native.prevent轉載于:https://www.cnblogs.com/smzd/p/9197915.html

mybatis中#和$區別

在Mybtis中的Mapper映射文件中&#xff0c;sql語句傳參有兩種方式#{}和${} 一般來說&#xff0c;我們通常使用的是#{}&#xff0c;這里采用的是預編譯機制&#xff0c;防止SQL注入&#xff0c;將#{}中的參數轉義成字符串&#xff0c;例如&#xff1a; 執行SQL&#xff1a;Selec…

mysql 字段存儲多個值 ,判斷一個值是否在其中

表C_file,其中有個字段是spile&#xff0c;他存的是字符形式&#xff0c;例如&#xff1a; id spile 1 2,10,11 2 2,3,20,22 3 1,6,8 4 5,6,1,9 select * from C_file where spile LIKE %1% 如果這樣查詢的話&#xff0c;會查詢出ID為1、3、4&#xff0c;但正確的應該是3、…

touchWX 自定義組件以及傳值

創建如圖文件 index.wxc: <template><view class"wx-test" bindtap"handleTap">{{ msg }}{{dataIndex}}</view> </template> <script>export default {properties: {dataIndex: {type: String,value: default value,}},data…