题目链接:https://leetcode.com/problems/wildcard-matching/

题目:

'?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false


思路:

看到tag是backtracking,dp,先用回溯试着做一下,首先思考如何把匹配问题转为为回溯问题,可以将模式串看成一棵类似于“子集树”,即对*号可以选择使用这个*匹配待匹配串某字符,也可选择不使用,使用完这个*匹配某字符后又可以将*留给下一个字符做匹配,做出来应该能过所有case,不过有几个case时间在秒级别,TLE了。 而且代码越写到后面越像dp。

遂考虑dp,dp思路就简单了,二维数组dp[i][j]表示两个分别为0~i(待匹配串),0~j(模式串)的串是否能匹配,状态转移方程:

1.当s[i]==p[j] 或者p[j]=='?': dp[i][j]=dp[i-1][j-1]

2.当p[j]=='*':dp[i][j]= 如果dp[k][j-1] k<=i,有为true的,即待匹配串是startwith(p[:j-1])的,那么待匹配串剩余部分可以由*匹配。

3.其他情况dp[i][j]默认为false

这个时间复杂度是O(n^3)的,AC之后只能超过1.08%的解法。 遂考虑优化,我们发现上面第2种情况是需要遍历才能知道p[:j-1]是否是startwiths[:i]的,这个遍历是可以省略的,用一个flag表示当前模式串p[:j-1]是否startwith s[:i],首先将遍历过程改为 【先让某个模式字符对所有带匹配串进行匹配】也就是将对P的for遍历放在前面,这样如果 ab能startwith abc则ab也一定startwith abcd,这样就少了一层遍历,时间复杂度降为O(n^2),不过AC之后也只能超过5%的解法。。。。泪

算法1:

public boolean isMatch(String s, String p) {
		dfs(s, 0, p, 0);
		return flag;
	}

	boolean flag = false;

	public void dfs(String s, int i, String p, int j) {
		if (flag) // 已经有一条路径可以匹配 则返回
			return;
		if (i == s.length()) {
			while (j < p.length()) {// 待匹配串已经匹配完,模式串如果剩余部分全为* 则返回true
				if (p.charAt(j) != '*') {
					return;
				}
				j++;
			}
			flag = true;
			return;
		}
		if (j == p.length())
			return;

		if (p.charAt(j) == '?' || p.charAt(j) == s.charAt(i)) {
			dfs(s, i + 1, p, j + 1);
		} else if (p.charAt(j) == '*') {// 如果模式串是*
			// 选择*作为s的匹配
			dfs(s, i + 1, p, j);
			dfs(s, i + 1, p, j + 1);
			// 不选择*
			dfs(s, i, p, j + 1);
		}
	}



算法2:


public boolean isMatch(String s, String p) {
		boolean dp[][] = new boolean[s.length() + 1][p.length() + 1];
		dp[0][0] = true;

		for (int i = 0; i <= s.length(); i++) {
			for (int j = 1; j <= p.length(); j++) {
				char pc = p.charAt(j - 1);
				if (i > 0 && (pc == '?' || pc == s.charAt(i - 1))) {
					dp[i][j] = dp[i - 1][j - 1];
				} else if (pc == '*') {
					for (int k = i; k >= 0; k--) {// 0~j-1的模式串是否能startwith匹配字符串0~i部分
						if (dp[k][j - 1]) {
							dp[i][j] = true;
							break;
						}
					}
				}
			}
		}
		return dp[s.length()][p.length()];
	}





算法3:

public boolean isMatch(String s, String p) {
		boolean dp[][] = new boolean[s.length() + 1][p.length() + 1];
		dp[0][0] = true;

		for (int j = 1; j <= p.length(); j++) {
			char pc = p.charAt(j - 1);
			boolean flag = false;
			for (int i = 0; i <= s.length(); i++) {
				flag = flag||dp[i][j-1];
				if (i > 0 && (pc == '?' || pc == s.charAt(i - 1))) {
					dp[i][j] = dp[i - 1][j - 1];
				} else if (pc == '*') {
					dp[i][j] = flag;
				}
			}
		}
		return dp[s.length()][p.length()];
	}