Description
Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for ‘?’ and ‘*’.
1 2
| '?' Matches any single character. '*' Matches any sequence of characters (including the empty sequence).
|
The matching should cover the entire input string (not partial).
Note:
- s could be empty and contains only lowercase letters a-z.
- p could be empty and contains only lowercase letters a-z, and characters like ? or *.
Example 1:
1 2 3 4 5
| Input: s = "aa" p = "a" Output: false Explanation: "a" does not match the entire string "aa".
|
Example 2:
1 2 3 4 5
| Input: s = "aa" p = "*" Output: true Explanation: '*' matches any sequence.
|
Example 3:
1 2 3 4 5
| Input: s = "cb" p = "?a" Output: false Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.
|
Example 4:
1 2 3 4 5
| Input: s = "adceb" p = "*a*b" Output: true Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".
|
Example 5:
1 2 3 4
| Input: s = "acdcb" p = "a*c?b" Output: false
|
Difficulty: Hard
Code:
1 2 3 4 5
| class Solution { public boolean isMatch(String s, String p) { } }
|
题意
给定一个字符串s和模式p,实现通配符匹配,支持?和。?表示任意一个字符,表示任何字符串。
匹配是完全匹配,s可能为空或者只包含a-z,p可能为空或者包含a-z和?或*。
Solution 1
进行下列判断:
- p和s相等或者p为”*”,则直接返回true
- p是否为空,若p为空,则直接返回s是否为空
- s是否为空,若s为空,则p必须必须全部是*
- 若p[0]==’?’,则返回递归调用isMatch(s[1:],p[1:])
- 若p[0]==’*’,则要么星号没匹配上s中任何字符,通过递归调用isMatch(s,p[1:]);否则递归说明星号匹配上了递归调用isMatch(s[1:],p)
- 若p[0]不为’?’或’*’,比较p[0]==s[0]&&isMatch(s[1:],p[1:])
但是这段代码提交时发现超过时间限制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public boolean isMatch(String s, String p) { if(p.equals(s)||p.equals("*")) return true; if(p.isEmpty()) return s.isEmpty(); if(s.isEmpty()){ if(p.charAt(0)=='*'){ return isMatch(s,p.substring(1)); }else{ return false; } } if(p.charAt(0)=='?') return isMatch(s.substring(1),p.substring(1)); if(p.charAt(0)=='*'){ int n=1; while(n<p.length()&&p.charAt(n)=='*'){ n++; } p=p.substring(n-1); if(isMatch(s,p.substring(1))) return true; return isMatch(s.substring(1),p); } return p.charAt(0)==s.charAt(0) && isMatch(s.substring(1),p.substring(1)); } }
|
时间复杂度: O()。
空间复杂度: O()。
Solution 2
定义i、j为s和p当前遍历对位置,iStar、jStar为星号出现时在s和p中匹配的最新位置。
进行while循环,条件时i小于s的长度。进行下列判断:
- 若s[i]==p[j]或者p[j]==’?’,则i和j分别加1
- 若p[j]==’*’,则iStar=i,jStart=j,j++
- 若当前星号出现即iStar>=0时,p[jStar]可以在s中多向前匹配一位,则i回退到iStart++,j回退到jStar+1
- 若星号没出现则返回false
最后若s已经匹配完,但p还有剩余字符,则要判断p中剩余字符是否都是*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public boolean isMatch(String s, String p) { int i=0, j=0, iStar=-1, jStar=-1; while(i<s.length()){ if(j<p.length()&&(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?')){ i++; j++; }else if(j<p.length()&&p.charAt(j)=='*'){ iStar=i; jStar=j; j++; }else if(iStar>=0){ i=++iStar; j=jStar+1; }else{ return false; } } while(j<p.length()&&p.charAt(j)=='*') j++; return j==p.length(); } }
|
时间复杂度: O()。
空间复杂度: O()。
Solution 3
使用动态规划,定义dp[m+1][n+1],dp[i][j]表示s中的前i个字符组成的字符串和p中的前j个字符组成的字符串是否匹配。
初始化dp[0][0]为true,因为s和p都为空时应返回true。还有当s为空,p中都是星号时也返回true。
若p中第j个字符为星号,若星号匹配空串即dp[i][j-1]为true,则d[i][j]也为true;有dp[i-1][j]为true时星号也可再多匹配一个,则dp[i][j]也为true。
若p中第j个字符不为星号,则在直到dp[i-1][j-1]的情况下,看s[i-1]和p[j-1]是否匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public boolean isMatch(String s, String p) { int m=s.length(), n=p.length(); boolean[][] dp = new boolean[m+1][n+1]; dp[0][0] = true; for(int i=1;i<=n;i++){ if(p.charAt(i-1)=='*') dp[0][i]=dp[0][i-1]; } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ if(p.charAt(j-1)=='*'){ dp[i][j]=dp[i][j-1]||dp[i-1][j]; }else{ dp[i][j]=dp[i-1][j-1]&&(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='?'); } } } return dp[m][n]; } }
|
时间复杂度: O()。
空间复杂度: O()。
Solution 4
同解法1使用递归调用,但同时采用剪枝。递归方法返回但不是boolean而是int,有三种状态。0表示匹配到s到末尾,但是未匹配成功。1表示未匹配到s到末尾就失败了。2表示匹配成功。
若s和p都完成匹配则返回2。若s匹配完成,但p当前字符不是星号则返回0。若s未匹配完而p匹配完,返回1。
若s和p都匹配完成则对下一位字符递归调用。否则若p当前字符为星号,那么先跳过连续的星号,然后分别让星号匹配空串、1个字符、2个字符…
剪枝条件:当返回值为0或者2时,则返回,否则继续遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public boolean isMatch(String s, String p) { return helper(s, p, 0, 0) > 1; } public int helper(String s, String p, int i, int j){ if(i==s.length() && j==p.length()) return 2; if(i==s.length() && p.charAt(j)!='*') return 0; if(j==p.length()) return 1; if(i<s.length()&&(s.charAt(i)==p.charAt(j)||p.charAt(j)=='?')){ return helper(s, p, i+1, j+1); } if(p.charAt(j)=='*'){ if(j+1<p.length()&&p.charAt(j+1)=='*'){ return helper(s,p,i,j+1); } for(int k=0;k<=s.length()-i;k++){ int res=helper(s,p,i+k,j+1); if(res==0||res==2) return res; } } return 1; } }
|
时间复杂度: O()。
空间复杂度: O()。