No.010:Regular Expression Matching

来源:http://www.cnblogs.com/jing-an-feng-shao/archive/2016/09/30/5923536.html
-Advertisement-
Play Games

題目: Implement regular expression matching with support for '.' and '*'.'.' Matches any single character.'*' Matches zero or more of the preceding elem ...


題目:

Implement regular expression matching with support for '.' and '*'.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Some Examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
isMatch("aab", ".*a") → false
isMatch("aab", ".*ab") → true

官方難度:

Hard

翻譯:

實現字元串正則表達式匹配,支持特殊符號"."和"*"。

"."可以匹配任意單個字元。

"*"可以匹配0個或更多的在*之前的字元。

匹配演算法應該能夠匹配以下所有的例子,而非部分。

例子:

isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
isMatch("aab", ".*a") → false
isMatch("aab", ".*ab") → true

思路:

1.只考慮正則表達式的匹配字元串只包括"*"和"."兩種特殊符號,其餘特殊符號(包括括弧)不在考慮範圍之內。

2.以待解析的字元串長度為基準,開始遍歷。

3.如果遍歷途中,出現待解析字元串尚存,而正則字元串不在了,或反之的情況,返回失敗。

4.從第一個字元開始,不考慮特殊符號的情況下,若匹配,進行待解析和正則字元串的下一個匹配工作。

5.特殊字元串"."單獨出現的情況,當次匹配直接通過。

6.特殊字元串"*"單獨出現的情況,計算"*"上一個字元在待解析字元串中的長度,待解析字元串在下次計算中會跳過那個長度(包括0的情況)。

7.特殊字元串".*"組合出現的情況,這種情況可以匹配,任意長,任意內容的字元串。如".*"可以匹配"abhsjksdhak",".*a"可以匹配"dhaudhjoaidhaida"但是不能匹配"bdab"。

8.出現7的情況,需要考慮,遍歷待解析字元串剩餘部分,能否匹配正則字元串".*"之後的部分。如"ab.*c.d"和"abctucid",需要依次檢查"ctucid"是否匹配"c.d","tucid"是否匹配"c.d",直至"d"是否匹配"c.d",只要存在一次匹配成功,就返回true。

解題中可能遇到的困難:

1.註意待解析字元串遍歷完畢之後,需要對正則字元串的長度做檢驗。

2.".*"的處理的方法,是和任意字元+"*"的方法寫在一起的,返回值是一個長度,註意處理結束返回一個特殊值,不要影響其他操作。

解題代碼:

 1 private static boolean method(String str, String regularStr) {
 2         String strWithoutHead = str;
 3         String regularStrWithoutHead = regularStr;
 4         int alreadyMatchedLength = 0;
 5         // 待處理的正則字元串
 6         String regularStrToDeal = null;
 7         int strLengthToReduce;
 8         while (alreadyMatchedLength < str.length()) {
 9             // 因為退出條件是解析完成字元串長度=原長度,
10             // 所以一次迴圈完成時,要判斷一下,正則的長度夠不夠
11             if (regularStrWithoutHead.length() == 0) {
12                 return false;
13             }
14             if (regularStrWithoutHead.length() > 1 && regularStrWithoutHead.substring(1, 2).equals("*")) {
15                 // 第二個數是"*"情況
16                 regularStrToDeal = regularStrWithoutHead.substring(0, 2);
17                 // 考慮到".*"的情況,把剩餘整個正則和待處理字元串傳進去
18                 strLengthToReduce = matchStarLength(strWithoutHead, regularStrWithoutHead);
19                 // ".*"的特殊處理,因為有遞歸,這裡就是一個出口
20                 if (strLengthToReduce == -1) {
21                     return true;
22                 } else if (strLengthToReduce == -2) {
23                     return false;
24                 }
25             } else {
26                 // 單個匹配情況
27                 regularStrToDeal = regularStrWithoutHead.substring(0, 1);
28                 if (!singleStringMatch(strWithoutHead.substring(0, 1), regularStrToDeal)) {
29                     return false;
30                 }
31                 strLengthToReduce = 1;
32             }
33             // 增加已處理的字元串長度
34             alreadyMatchedLength += strLengthToReduce;
35             // 去頭
36             strWithoutHead = str.substring(alreadyMatchedLength);
37             regularStrWithoutHead = regularStrWithoutHead.substring(regularStrToDeal.length());
38         }
39         // 待解析完成,但正則還有
40         if (regularStrWithoutHead.length() > 0) {
41             return false;
42         }
43         return true;
44     }
45 
46     // 單個字元匹配問題
47     private static boolean singleStringMatch(String str, String regularStr) {
48         // 特殊符號"."處理
49         if (regularStr.equals(".")) {
50             return true;
51         } else if (str.equals(regularStr)) {
52             return true;
53         }
54         return false;
55     }
56 
57     // 由於"*"一定會匹配成功,返回原字元串的匹配長度
58     // str不是原字元串,是"*"開始匹配的第一個位置
59     private static int matchStarLength(String str, String regularString) {
60         int length = 0;
61         if (regularString.substring(0, 1).equals(".")) {
62             // 最最最煩的一點:".*"處理
63             // 先把對應的正則字元串去掉".*"
64             String regularRemain = regularString.substring(2);
65             // ".*"之後不跟,匹配一切
66             if (regularRemain.equals("")) {
67                 // 返回剩下的字元串長度
68                 return str.length();
69             }
70             // 用餘下的東西遞歸
71             for (int i = 0; i < str.length(); i++) {
72                 String remain = str.substring(i);
73                 // 開始遞歸
74                 if (method(remain, regularRemain)) {
75                     // 只要出現true,直接整個都可以匹配
76                     return -1;
77                 }
78             }
79             // 餘下的都不成功,表示整個不匹配
80             return -2;
81         } else {
82             // 正常字元+"*"
83             String regularInUse = regularString.substring(0, 1);
84             for (int i = 0; i < str.length(); i++) {
85                 if (regularInUse.equals(str.substring(i, i + 1))) {
86                     length++;
87                 } else {
88                     break;
89                 }
90             }
91         }
92         return length;
93     }
View Code

測試代碼地址:

https://github.com/Gerrard-Feng/LeetCode/blob/master/LeetCode/src/com/gerrard/algorithm/hard/Q010.java

LeetCode題目地址:

https://leetcode.com/problems/regular-expression-matching/

PS:寫完才發現,不使用迴圈待解析字元串,直接對剩餘的字元串使用遞歸,可能是一種更好的思想。

PPS:如有不正確或提高效率的方法,歡迎留言,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 字元串輸入 Python用到的輸入一般有兩種方式, 和 ,區別是,前者只能輸入數字,後者輸入的是字元串,使用如下: 字元串輸出 輸出使用 即可,後邊可加變數,也可以直接用"、'和'''來包含字元串,使用示例如下: 正常情況下均可以使用,可以使用一種包含一個字元串,字元串中可以包含另外一種(但是不可以 ...
  • 下載: 1.在spring-mvc中配置(用於100M以下的文件下載) <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messa ...
  • Thread提供了stop()方法終止線程,但是該方法是強行終止,容易產生一些錯誤,已經被廢棄。 可以使用退出標誌來終止線程,在run()函數裡面設置while迴圈,把退出標誌作為while的條件,當條件為false時,run函數執行完畢,線程就自動終止了。 ...
  • 不是所有的運算符都能重載, 以下的都不行 作用域運算符號 成員訪問運算符 成員指針解引用 求類型或者對象大小的運算符 三目運算符 類型信息運算符 寫重載時註意: 不要發明運算符重載,只能對已經有的運算符重載,不能發明運算符 不能對基本類型的運算符的進行重載= 運算符重載中至少有一個類型是類類型 不能 ...
  • 判斷一個字元串是否是數值,可以用正則表達式來判斷。更簡單的方法是把字元串轉換成Float或者Double,然後捕捉NumberFormatException錯誤,如果有錯誤,就說明不是一個數值,如果沒有錯誤,就說明就是一個數值。 同樣的方法,可以判斷一個字元串是否是整數。 ...
  • 在本地開發機中進行web項目的開發,部署到生產環境進行產品發佈時,需要將web應用的文件打包成war包,War包可以放在Tomcat下的webapps或者word目錄下,隨著tomcat伺服器的啟動,它可以自動被解壓。 這樣需要遠程上傳到webapps,調試起來比較麻煩。所以在發佈生產環境之前,最好 ...
  • 遞歸 反射 os模塊 sys模塊 hashlib加密模塊 正則表達式 反射 python中的反射功能是由以下四個內置函數提供:hasattr、getattr、setattr、delattr,改四個函數分別用於對對象內部執行:檢查是否含有某成員、獲取成員、設置成員、刪除成員。 os模塊 sys模塊 h ...
  • friend friend的聲明可以出現在授權類的public, protected 和private等任意區域, 把一個全局函數、另一個類的成員函數或另一個類聲明為授權類的friend,使它擁有訪問授權類任何成員的特權,有時為了簡化代碼的書寫,可以將友元的定義和聲明都放在授權類內,但它依然是友元而 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...