10正则表达式匹配 朴灿烈づ我的快乐病毒、 2023-03-01 10:23 1阅读 0赞 ## 一、前言 ## 标签:动态规划。 问题来源LeetCode 10 难度:困难。 问题链接:[https://leetcode-cn.com/problems/regular-expression-matching/][https_leetcode-cn.com_problems_regular-expression-matching] ## 二、题目 ## 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '\*' 的正则表达式匹配。 '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 **说明:** s 可能为空,且只包含从 a-z 的小写字母。 p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 **示例 1:** 输入: s = "aa" p = "a" 输出: false 解释: "a" 无法匹配 "aa" 整个字符串。 **示例 2:** 输入: s = "aa" p = "a*" 输出: true 解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。 **示例 3:** 输入: s = "ab" p = ".*" 输出: true 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。 **示例 4:** 输入: s = "aab" p = "c*a*b" 输出: true 解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。 **示例 5:** 输入: s = "mississippi" p = "mis*is*p*." 输出: false ## 三、思路 ## ### 3.1 题意 【\*】 ### '\*' 匹配零个或多个前面的那一个元素,匹配0个意思是前面字符和\*一起忽略,而不是只保留前面字符。例如:ab\*,可以表示为,abb,abbb,a。当\*匹配零个前面字符 ab\* 表示为a。 ### 3.2 动态规划解题 ### 本题用动态规划解决。 我们用f\[i\]\[j\] 表示 s 的前 i 个字符与 p 中的前 j 个字符是否能够匹配。在进行状态转移时,我们考虑 p 的第 j 个字符的匹配情况: * 如果 p 的第 j 个字符是一个小写字母,那么我们必须在 s 中匹配一个相同的小写字母,即 ![20200724092357932.png][] 也就是说,如果 ss 的第 ii 个字符与 pp 的第 jj 个字符不相同,那么无法进行匹配;否则我们可以匹配两个字符串的最后一个字符,完整的匹配结果取决于两个字符串前面的部分。 * 如果 p 的第 j 个字符是 \*,那么就表示我们可以对 p 的第 j−1 个字符匹配任意自然数次。在匹配 0 次的情况下,我们有 f\[i\]\[j\]=f\[i\]\[j−2\] 也就是我们「浪费」了一个字符 + 星号的组合,没有匹配任何 s 中的字符。 在匹配 1,2,3, ⋯ 次的情况下,类似地我们有 f\[i\]\[j\] = f\[i−1\]\[j−2\], if s\[i\] = p\[j−1\] f\[i\]\[j\] = f\[i−2\]\[j−2\], if s\[i−1\] = s\[i\]=p\[j−1\] f\[i\]\[j\] = f\[i−3\]\[j−2\], if s\[i−2\] = s\[i−1\] = s\[i\] = p\[j−1\] ⋯⋯ 如果我们通过这种方法进行转移,那么我们就需要枚举这个组合到底匹配了 s 中的几个字符,会增导致时间复杂度增加,并且代码编写起来十分麻烦。我们不妨换个角度考虑这个问题:字母 + 星号的组合在匹配的过程中,本质上只会有两种情况: * 匹配 s 末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配; * 不匹配字符,将该组合扔掉,不再进行匹配。 如果按照这个角度进行思考,我们可以写出很精巧的状态转移方程: ![20200724092605436.png][] * 在任意情况下,只要 p\[j\] 是 .,那么 p\[j\] 一定成功匹配 s 中的任意一个小写字母。 最终的状态转移方程如下: ![20200724092630260.png][] 其中 matches(x,y) 判断两个字符是否匹配的辅助函数。只有当 y 是 . 或者 x 和 y 本身相同时,这两个字符才会匹配。 ## 四、编码实现 ## //========================================================================== /* * @file : 10_IsMatch.h * @label : 动态规划 * @blogs : https://blog.csdn.net/nie2314550441/article/details/107553494 * @author : niebingyu * @date : 2020/07/23 * @title : 10.正则表达式匹配 * @purpose : 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。 * '.' 匹配任意单个字符 * '*' 匹配零个或多个前面的那一个元素 * 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 * * 说明: * s 可能为空,且只包含从 a-z 的小写字母。 * p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 * * * * 来源:力扣(LeetCode) * 难度:困难 * 链接:https://leetcode-cn.com/problems/regular-expression-matching/ */ //========================================================================== #pragma once #include <iostream> #include <vector> #include <algorithm> #include <assert.h> using namespace std; #define NAMESPACE_ISMATCH namespace NAME_ISMATCH { #define NAMESPACE_ISMATCHEND } NAMESPACE_ISMATCH class Solution { public: bool isMatch(string s, string p) { int m = s.size(); int n = p.size(); auto matches = [&](int i, int j) { if (i == 0) return false; if (p[j - 1] == '.') return true; return s[i - 1] == p[j - 1]; }; vector<vector<int>> f(m + 1, vector<int>(n + 1)); f[0][0] = true; for (int i = 0; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (p[j - 1] == '*') { f[i][j] |= f[i][j - 2]; if (matches(i, j - 1)) f[i][j] |= f[i - 1][j]; } else { if (matches(i, j)) f[i][j] |= f[i - 1][j - 1]; } } } return f[m][n]; } }; 以下为测试代码// // 测试 用例 START void test(const char* testName, string str, string p, bool expect) { Solution s; bool result = s.isMatch(str, p); if (result == expect) cout << testName << ", solution passed." << endl; else cout << testName << ", solution failed. " << endl; } // 测试用例 void Test1() { string st = "aa"; string p = "a*"; bool expect = true; test("Test1()", st, p, expect); } void Test2() { string st = "aab"; string p = "c*a*b"; bool expect = true; test("Test2()", st, p, expect); } void Test3() { string st = "mississippi"; string p = "mis*is*p*."; bool expect = false; test("Test3()", st, p, expect); } NAMESPACE_ISMATCHEND // 测试 用例 END // void IsMatch_Test() { cout << "------ start 10.正则表达式匹配 ------" << endl; NAME_ISMATCH::Test1(); NAME_ISMATCH::Test2(); NAME_ISMATCH::Test3(); cout << "------ end 10.正则表达式匹配 --------" << endl; } **执行结果:** ![20200724093004911.png][] [https_leetcode-cn.com_problems_regular-expression-matching]: https://leetcode-cn.com/problems/regular-expression-matching/ [20200724092357932.png]: /images/20230209/e8cb2a4911c441408f127755a2c44fc7.png [20200724092605436.png]: /images/20230209/818a2365c5f1449c85fdcf496a9daa20.png [20200724092630260.png]: /images/20230209/c5c36b971974488e978b1565ae74d25d.png [20200724093004911.png]: /images/20230209/068978828bfc48788923cd50ec7c652c.png
还没有评论,来说两句吧...