leetcode44_通配符匹配_动态规划

题目链接:44. 通配符匹配 - 力扣(LeetCode)

题目大意:

给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:

  • '?' 可以匹配任何单个字符。
  • '*' 可以匹配任意字符序列(包括空字符序列)。

判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

 

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "*"
输出:true
解释:'*' 可以匹配任意字符串。

示例 3:

输入:s = "cb", p = "?a"
输出:false
解释:'?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。

提示:

  • 0 <= s.length, p.length <= 2000
  • s 仅由小写英文字母组成
  • p 仅由小写英文字母、'?' 或 '*' 组成

题目思路:

先通过递归理清关系,再记忆化搜索减少不必要的递归,最后动态规划实现

题目代码:

1.记忆化搜索

class Solution {
#define N 2010
typedef long long ll;
int n, m;
int dp[N][N];//-1,0,1
public:
bool f(string& s,string& p,int i,int j)
{
	if (dp[i][j] != -1) {
		return dp[i][j];
	}

	bool ans = false;
	if (i == n) {
		if (j == m) {
			ans = true;
		}
		else {
			if (p[j] == '*') {
				ans= f(s, p, i, j + 1);
			}
			else {
				ans = false;
			}
		}
	}
	else {//i!=n
		if (j == m) {
			ans = false;
		}
		else {//j!=m
			if (s[i] == p[j] || p[j]=='?') {
				ans = f(s, p, i + 1, j + 1);
			}
			else if (p[j] == '*') {
				for (int k = i; k <= n;++k) {
					ans = ans || f(s, p, k, j + 1);
				}
			}
			else {
				ans = false;
			}
		}
	}
	dp[i][j] = ans;
	return ans;	
}

bool isMatch(string s, string p) {
	memset(dp, -1, sizeof(dp));
	n = s.size();
	m = p.size();
	return f(s, p, 0, 0);
}
};

2.动态规划 

class Solution {
#define N 2010
typedef long long ll;
int n, m;
int dp[N][N];//-1,0,1
public:
bool isMatch(string s, string p) {
	memset(dp, 0, sizeof(dp));
	n = s.size();
	m = p.size();
	dp[n][m] = 1;
	for (int j = m - 1;j >= 0;--j) {
		if (p[j] == '*') {
			dp[n][j] = dp[n][j + 1];
		}
	}
	for (int i = n - 1;i >= 0;--i) {
		for (int j = m - 1;j >= 0;--j) {
			if (s[i] == p[j] || p[j] == '?') {
				dp[i][j] = dp[i + 1][j + 1];
			}
			else if (p[j] == '*') {
				for (int k = i; k <= n;++k) {
					dp[i][j] = dp[i][j] || dp[k][j + 1];
				}
			}
		}
	}
	return dp[0][0];
}

};

3.优化枚举 

class Solution {
#define N 2010
typedef long long ll;
int n, m;
int dp[N][N];//-1,0,1
public:
bool isMatch(string s, string p) {
	memset(dp, 0, sizeof(dp));
	n = s.size();
	m = p.size();
	dp[n][m] = 1;
	for (int j = m - 1;j >= 0;--j) {
		if (p[j] == '*') {
			dp[n][j] = dp[n][j + 1];
		}
	}
	for (int i = n - 1;i >= 0;--i) {
		for (int j = m - 1;j >= 0;--j) {
			if (s[i] == p[j] || p[j] == '?') {
				dp[i][j] = dp[i + 1][j + 1];
			}
			else if (p[j] == '*') {
                dp[i][j] = dp[i][j + 1] || dp[i + 1][j];
			}
        }
	}
	return dp[0][0];
}

};

4.使用vector减少无用的空间(数据量小的时候明显)

class Solution {
#define N 2010
typedef long long ll;
int n, m;
public:
bool isMatch(string s, string p) {
	n = s.size();
	m = p.size();
    vector<vector<int>> dp(n+1,vector<int>(m+1));
	dp[n][m] = 1;
	for (int j = m - 1;j >= 0;--j) {
		if (p[j] == '*') {
			dp[n][j] = dp[n][j + 1];
		}
	}
	for (int i = n - 1;i >= 0;--i) {
		for (int j = m - 1;j >= 0;--j) {
			if (s[i] == p[j] || p[j] == '?') {
				dp[i][j] = dp[i + 1][j + 1];
			}
			else if (p[j] == '*') {
                dp[i][j] = dp[i][j + 1] || dp[i + 1][j];
			}
        }
	}
	return dp[0][0];
}

};

5. 空间压缩(注意很多特殊情况的细节,空间足够的话不必要)

class Solution {
#define N 2010
typedef long long ll;
int n, m;
bool dp[N];
public:
bool isMatch(string s, string p) {
	memset(dp, 0, sizeof(dp));
	n = s.size();
	m = p.size();
    if(n==0 && m==0) return true;
    if(m==0) return false;
	dp[m] = 1;
	for (int j = m - 1;j >= 0;--j) {
		if (p[j] == '*') {
			dp[j] = dp[j + 1];
		}
	}



	for (int i = n - 1;i >= 0;--i) {
		int rd = i == n - 1 ? 1 : 0;
		for (int j = m - 1;j >= 0;--j) {
			int cur = dp[j];
			if (s[i] == p[j] || p[j] == '?') {
				dp[j] = rd;
			}
			else if (p[j] == '*') {
				dp[j] = cur || dp[j + 1];
			}
			else if (s[i] != p[j]) {
				dp[j] = 0;
			}
			rd = cur;
		}
	}


	return dp[0];
}

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值