[程序员代码面试指南]字符串问题-字符串匹配问题(DP)

问题描述

  • 字符串str,模式串exp。
  • 必须保证str中无'.'和'星号'字符,并且exp中'星号'不出现在首位,且无连续两个'星号'。PS星号是字符只是暂时没找到markdown的星号转义字符。
  • '.'可以匹配任意一个字符,'星号'可以匹配0-多个星号前面的一个字符的情况。
  • 输出可否匹配。
  • 例:
    str="abc",exp="a.c" ,true
    str="abc",exp=".星号",true
    str="",exp="..星号",false

解题思路

  • 递归思路写成DP。时间复杂度O(N^2*M), 其中N为str的长度。
  • 具体的,
    • dp[i][j]表示str[i:str.length]能否匹配exp[j:exp.length]
    • 开dp[str.length()+1][exp.length()+1]
    • dp[i][j]只依赖于dp[i+k(k>=0)][j+2]或者dp[i+1][j+1],所以初始化最后一行和最后两列,具体初始化看书,并由右下角开始遍历即可。
    • 分以下情况讨论转移,具体见书P318.
      • 当前位置exp的下一位不是'星号'
      • 当前位置exp的下一位是'星号'
        • 当前字符匹配
        • 当前字符不匹配

代码

public class Main {
	public static void main(String args[]) {
		String str="";
		String exp=".*";
		boolean match=isMatch(str,exp);
		System.out.println(match);
	}
	
	public static boolean isMatch(String str,String exp) {
		if(!isValid(str,exp)) {
			return false;
		}
		boolean[][] dp=new boolean[str.length()+1][exp.length()+1];
		init(dp,str,exp);
		
		for(int i=str.length()-1;i>=0;--i) {
			for(int j=exp.length()-2;j>=0;--j) {
				if(exp.charAt(j+1)!='*') {//下一位是星号
					if((str.charAt(i)==exp.charAt(j)||exp.charAt(j)=='.')&&dp[i+1][j+1]) {//
						dp[i][j]=true;
					}
				}
				else {//下一位不是星号
					for(int ii=i;i<str.length()&&((str.charAt(ii)==exp.charAt(j)||exp.charAt(j)=='.'));++ii) {//当前位置可以匹配 //
							if(dp[ii+1][j+2]) {
								dp[i][j]=true;
								break;
							}
					}
					if(!dp[i][j]) {//当前位置不可以匹配
						dp[i][j]=dp[i][j+2];
					}
				}
			}
		}
		
		return dp[0][0];
	}
	
	public static boolean isValid(String str,String exp) {
		for(int i=0;i<str.length();++i) {
			if(str.charAt(i)=='.'||str.charAt(i)=='*') {
				return false;
			}
		}
		for(int i=0;i<exp.length();++i) {
			if(exp.charAt(i)=='*'&&(i==0)||i!=0&&exp.charAt(i-1)=='*') {
				return false;
			}
		}
		return true;
	}
	
	public static void init(boolean[][] dp,String str,String exp) {
		for(int i=0;i<=str.length();++i) {//包含初始化最后一列
			for(int j=0;j<=exp.length();++j) {
				dp[i][j]=false;
			}
		}
		dp[str.length()][exp.length()]=true;

		if(str.length()>0&&exp.length()>0) {//初始化倒数第二列 //
			if(str.charAt(str.length()-1)==exp.charAt(exp.length()-1)||exp.charAt(exp.length()-1)=='.') {
				dp[str.length()-1][exp.length()-1]=true;
			}
		}
		
		for(int j=exp.length()-2;j>=0;j=j-2) {//初始化最后一行
			if(exp.charAt(j+1)=='*') {//
				dp[str.length()][j]=true;
			}
			else {
				break;
			}
		}
	}
}

posted on 2019-05-15 22:06  coding_gaga  阅读(352)  评论(0编辑  收藏  举报

导航