力扣10.正则表达式匹配

题目:传送门
题意: 给你两个字符串s和p,p字符串中有“.”和“ * ”这两种特殊字符,“.”可以匹配任意字符,“ * ”代表它的前一个字符的个数,可以是0也可以是无数个,现在问s和p是否匹配,题意这点比较模糊,题目中说涵盖,涵盖我最开始的理解是包含,但是不是,题目的意思是通过对这两个特殊字符的转换使两个字符串相等。
思考: 我最开始的思路是使用函数递归,但是当时我理解的题意是包含,对于“ * ”这个情况不能很好的处理,然后我的方法是动态规划,开辟dp[x][y]这样一个二维数组,dp[x][y]代表的意思就是s[x]和p[y]之前的字符的匹配状况,如果使用动态规划,我们就必须明天这一状态下它的结果是受什么决定的。
在这里插入图片描述
这就是某一时刻的状态,以及这个状态的值的可能。但是我们还要考虑一些特殊的情况,首先,s可能为空,这个时候,我是单独判断p字符串,判断该字符串能否通过“ * ”把p消为0,这一部分代码:

if (m == 0) {
    
    
		for (int i = 0; i < n; i++) {
    
    
			if (p[i] != '*' && i + 1 <= n && p[i + 1] != '*')
				return false;
			if (i == n - 1 && p[i] != '*')
				return false;
		}
		return true;
	}

然后还有一种情况,s=“ab”,p=“ccab”,我需要把前面的字符消除,这个只会影响第一个字符的判断,所以:

if (i == 1) {
    
    
					int k = j;
					while (k >= 3&&p[k-2]=='*') {
    
    
						dp[i][j] |= dp[i - 1][k - 3];
						k -= 2;
					}
				}

我用一个while循环来解决这个问题。
上代码:

#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Solution
{
    
    
public:
	bool isMatch(string s, string p);
	bool compare(string s, string p, int i, int j);
};

bool Solution::isMatch(string s, string p) {
    
    
	int m = s.length();
	int n = p.length();
	if (m == 0) {
    
    
		for (int i = 0; i < n; i++) {
    
    
			if (p[i] != '*' && i + 1 <= n && p[i + 1] != '*')
				return false;
			if (i == n - 1 && p[i] != '*')
				return false;
		}
		return true;
	}
	vector<vector<int>>dp(m + 1, vector<int>(n + 1));
	dp[0][0] = true;
	for (int i = 1; i <= m; i++) {
    
    
		for (int j = 1; j <= n; j++) {
    
    
			if (p[j - 1] == '*') {
    
    
				dp[i][j] |= dp[i][j - 2];//*=0
				dp[i][j] |= dp[i][j - 1];//*=1
				if (compare(s, p, i, j - 1)) {
    
    //*>=2
					dp[i][j] |= dp[i - 1][j];
				}

			}
			else {
    
    
				if (compare(s, p, i, j)) {
    
    
					dp[i][j] |= dp[i - 1][j - 1];
				}
				if (i == 1) {
    
    
					int k = j;
					while (k >= 3&&p[k-2]=='*') {
    
    
						dp[i][j] |= dp[i - 1][k - 3];
						k -= 2;
					}
				}
			}
			//cout << "dp[" << i << "]" << "[" << j << "]=" << dp[i][j] << endl;
		}
	}
	return dp[m][n];
}

bool Solution::compare(string s, string p, int i, int j) {
    
    
	if (p[j - 1] == '.')
		return true;
	return s[i - 1] == p[j - 1];
}

int main() {
    
    
	string s, p;
	cin >> s >> p;
	Solution ans;
	if (ans.isMatch(s, p)) {
    
    
        cout << "true" << endl;
	}
	else {
    
    
		cout << "false" << endl;
	}
	
	return 0;
}

动态规划问题的要点在于找到状态方程,也就是找到在某种状态下它的结果,将问题划分子问题。如果你的状态方程找的包含的情况越多,这说明你找的状态方程越好,就像我的的代码,对一下特殊情况的时候需要单独拿出来,我的状态方程就不好,状态方程找好之后,你还要思考如何对状态方程进行处理,让我们欣赏官方题解:

class Solution
{
    
    
public:
	bool isMatch(string s, string p);
	bool compare(string s, string p, int i, int j);
};

bool Solution::isMatch(string s, string p) {
    
    
	int m = s.length();
	int n = p.length();
	vector<vector<int>>dp(m + 1, vector<int>(n + 1));
	dp[0][0] = true;
	for (int i = 0; i <=m; i++) {
    
    
		for (int j = 1; j <=n; j++) {
    
    
			if (p[j - 1] == '*') {
    
    
				dp[i][j] |= dp[i][j - 2];
				if (compare(s, p, i, j - 1)) {
    
    
					dp[i][j] |= dp[i-1][j];
				}
			}
			else {
    
    
				if (compare(s, p, i, j)) {
    
    
					dp[i][j] |= dp[i - 1][j - 1];
				}
			}
		}
	}
	return dp[m][n];
}

bool Solution::compare(string s, string p, int i, int j) {
    
    
	if (i == 0)
		return false;
	if (p[j - 1] == '.')
		return true;
	return s[i - 1] == p[j - 1];
}

对比之下,我们能发现别人的代码更加简洁,对数据的处理,动态规划的应用都要更加优秀。
ヾ(◍°∇°◍)ノ゙
在这里插入图片描述

Guess you like

Origin blog.csdn.net/qq_43840681/article/details/117964886