程序员代码面试指南:字符串匹配问题
字符串匹配问题
http://www.nowcoder.com/questionTerminal/7ab95c2bbfc941a89c13c78128914e14
题目链接:https://www.nowcoder.com/practice/7ab95c2bbfc941a89c13c78128914e14?tpId=101&tqId=33204&tPage=7&rp=7&ru=/ta/programmer-code-interview-guide&qru=/ta/programmer-code-interview-guide/question-ranking
题目描述
对于字符串str,其中绝对不含有字符’.’和‘’。再给定字符串exp,其中可以含有’.’或’‘’,’’字符不能是exp的首字符,并且任意两个’‘字符不相邻。exp中的’.’代表任何一个字符,exp中的’’表示’‘的前一个字符可以有0个或者多个。请写一个函数,判断str是否能被exp匹配(注意:输入的数据不保证合法,但只含小写字母和‘.’和‘*’)。
输入包含两行,两个字符串,分别代表str和exp(str和len长度大于等于1小于等于300)
如果str是能被exp匹配,请输出“YES”,否则输出“NO”。
采用动态规划的思路,dp[i][j]表示str[i]到str最后一个字符和exp[j]到exp最后一个字符是否匹配。
我们分三种情况讨论:
1、exp[j]是字母。如果exp[j+1]不是*号,则exp[j]必须匹配str[i]的第一个字符,接下来就判断str[i+1]到最后和exp[j+1]到最后是否匹配,所以:
dp[i][j]=(str[i]==exp[j] && dp[i+1][j+1])
如果exp[j+1]是星号的话,那么exp[j]可以有0个或多个,如果exp[j]有0个,等价于str[i]到最后和exp[j+2]到最后是否匹配,如果exp[j]有多个,则首先匹配exp[j]和str[i],由于exp[j]可以有多个,所以之后可能还会有exp[j]和str[i]的字符匹配,此时等价于str[i+1]到最后和exp[j]是否匹配,所以当exp[j+1]是星号的话,可以得到:
dp[i][j]=dp[i][j+2] || (str[i]==exp[j] && dp[i+1][j])
2、exp[j]是字符'.'的时候,与情况1类似,由于'.'可以匹配任意字符,所以求解dp的时候删去str[i]==exp[j]的判断就可以。
3、exp[j]是星号'*',此时exp[j]前面的字符可以有一个或多个,分情况讨论即可:首先如果有0个exp[j+1]判断str[i]到最后和exp[j+1]到最后是否匹配。
接着设定变量k,初始k=i,如果str[k]==exp[j-1],此时表示有一个exp[j-1],此时判断str[k+1]到最后和exp[j+1]到最后是否匹配,如果不匹配:
k=i+1,如果str[k]==exp[j-1],此时表示有两个exp[j-1],再判断str[k+1]到最后和exp[j+1]到最后是否匹配,如果不匹配,k=i+2,以此类推,如果在这个过程中,str[k+1]和exp[j+1]匹配了,则dp[i][j]=true,如果遍历到str[k]!=exp[j-1]或者k到了str最后,则dp[i][j]=false。
最后处理一下边界条件,我是这么处理的:设length(str)=n,length(exp)=m,则dp[n][m]=true,dp[i][m]=false(0<=i<n)。
如果exp[j]=='',则dp[n][j]=dp[n][j+1]。
如果exp[j]!=''且exp[j+1]=='*',则dp[n][j]=dp[n][j+2]
否则,dp[n][j]=false
package main import( "fmt" ) var str,exp string func main(){ fmt.Scan(&str) fmt.Scan(&exp) solve() } func solve(){ n,m:=len(str),len(exp) for _,v:=range str{ if !(v>='a' && v<='z'){ fmt.Println("NO") return } } for i,v:=range exp{ if i==0 && exp[i]=='*'{ fmt.Println("NO") return } if exp[i]=='*' && i+1<m && exp[i+1]=='*'{ fmt.Println("NO") return } if !((v>='a' && v<='z') || (v=='.') || (v=='*')){ fmt.Println("NO") return } } dp:=make([][]bool,n+1) for i:=0;i<=n;i++{ dp[i]=make([]bool,m+1) } for i:=0;i<=n;i++{ for j:=0;j<=m;j++{ dp[i][j]=false } } for i:=n;i>=0;i--{ for j:=m;j>=0;j--{ if j==m{ dp[i][j]=(i==n) }else if i==n{ if exp[j]=='*'{ dp[i][j]=dp[i][j+1] }else if j+1<m && exp[j+1]=='*'{ dp[i][j]=dp[i][j+2] } }else if exp[j]=='.'{ if j+1<m && exp[j+1]=='*'{ dp[i][j]=(dp[i][j+2]) || (dp[i+1][j]) }else{ dp[i][j]=dp[i+1][j+1] } }else if exp[j]=='*'{ //*之前0个字符 if dp[i][j+1]{ dp[i][j]=true continue } //*之前多于0个字符 for k:=i;k<n;k++{ if exp[j-1]!='.' && str[k]!=exp[j-1]{ break }else if dp[k+1][j+1]{ dp[i][j]=true break } } }else{ if j+1<m && exp[j+1]=='*'{ dp[i][j]=(dp[i][j+2]) || (str[i]==exp[j] && dp[i+1][j]) }else{ dp[i][j]=(str[i]==exp[j] && dp[i+1][j+1]) } } } } if dp[0][0]{ fmt.Println("YES") }else{ fmt.Println("NO") } }