题目:传送门
题意: 给你两个字符串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];
}
对比之下,我们能发现别人的代码更加简洁,对数据的处理,动态规划的应用都要更加优秀。
ヾ(◍°∇°◍)ノ゙