您的位置:首页 > 其它

Leetcode44 Wildcard Matching

2015-08-07 12:10 309 查看

Wildcard Matching

Implement wildcard pattern matching with support for ‘?’ 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

Solution1

最简单的是递归,在《剑指offer》里也有类似的题目,便是用递归来解决的

public class Solution {
public boolean isMatch(String s, String p) {
return isMatch(s,p,0,0);
}
public boolean isMatch(String s,String p,int i,int j){
if(i==s.length()&&j==p.length()) return true;
if(i>s.length()||j==p.length()) return false;//i已超出2个字符以上,或者j到了末尾但i还未结束
if(p.charAt(j)=='*') return isMatch(s,p,i,j+1)||isMatch(s,p,i+1,j+1)||isMatch(s,p,i+1,j);
if(i==s.length()) return false;
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?') return isMatch(s,p,i+1,j+1);
return false;
}
}


Solution2

解法一的递归极其低效,虽然能解,但是太耗时间。这里换一种递归方法

public class Solution {
public boolean isMatch(String s, String p) {
return isMatch(s,p,0,0);
}
public boolean isMatch(String s,String p,int i,int j){
if(i==s.length()&&j==p.length()) return true;
if(j==p.length()) return false;
if(p.charAt(j)=='*'){
while(j<p.length()&&p.charAt(j)=='*') j++;//将'*'都跳过
if(j==p.length()) return true;
if(p.charAt(j)!='?') while(i<s.length()&&s.charAt(i)!=p.charAt(j)) i++;
if(i==s.length()) return false;
return isMatch(s,p,i+1,j+1)||isMatch(s,p,i+1,j);
}
if(i==s.length()) return false;
if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?') return isMatch(s,p,i+1,j+1)||((j>0&&p.charAt(j-1)=='*')?isMatch(s,p,i+1,j):false);
return (j>0&&p.charAt(j-1)=='*')?isMatch(s,p,i+1,j):false;
}
}


Solution3

解法二比解法一要好很多,主要是跳过了星号的判断,可以节省不少时间,但是递归仍然重复了很多次判断,这时候必须考虑到动态规划的解法了。

一般说来,递归和动态规划有着明显的区别:递归往往都是从前至后或者从上往下(比如二叉树里面),而动态规划则往往都是从后往前或者从下往上(指思考过程,实际的运行过程仍然是从前往后从顶往下的,因为要记录中间过程)。动态规划的好处是在从后往前或从下往上的过程中,实际可以记录一些中间过程。这样便省去了很多重复过程。

public class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m+1][n+1];//dp[i][j]为s中的前i段能匹配到p中j处
dp[0][0] = true;
for(int j=0;j<n;j++){
dp[0][j+1] = dp[0][j]&&(p.charAt(j)=='*');
for(int i=0;i<m;i++){
if(p.charAt(j)=='*') dp[i+1][j+1] = dp[i+1][j]||dp[i][j]||dp[i][j+1];//此处的if-else语句便是本题动态规划的递推关系式
else dp[i+1][j+1] = dp[i][j]&&(p.charAt(j)=='?'||p.charAt(j)==s.charAt(i));
}
}
return dp[m]
;
}
}


Solution4

用滚动数组将解法三中的递推数组进一步简化为一维数组

public class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[] dp = new boolean[m+1];
dp[0] = true;
for(int j=0;j<n;j++){
if(p.charAt(j)=='*') for(int i=0;i<m;i++) dp[i+1] = dp[i+1]||dp[i];
else for(int i=m-1;i>=0;i--) dp[i+1] = dp[i]&&(p.charAt(j)=='?'||p.charAt(j)==s.charAt(i));
dp[0] = dp[0]&&(p.charAt(j)=='*');//这句话必须放在末尾
}
return dp[m];
}
}


Solution5

还有一种更精妙绝伦的解法。本质上是回溯法,但不需要递归,并且比递归效率高出很多。

非递归的回溯解法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode