zoukankan      html  css  js  c++  java
  • [程序员代码面试指南]字符串问题-字符串匹配问题(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;
    			}
    		}
    	}
    }
    
  • 相关阅读:
    linux下mysql基于mycat做主从复制和读写分离之基础篇
    HttpClient之基本使用
    查阅资料学习的书签(补充中.......)
    java架构《Socket网络编程基础篇》
    Redis常见配置文件详解
    redis学习教程五《管道、分区》
    redis学习教程四《管理、备份、客户端连接》
    js将json数组转成tree对象
    小程序转发事件生命周期
    mpvue开发小程序添加页面
  • 原文地址:https://www.cnblogs.com/coding-gaga/p/10872538.html
Copyright © 2011-2022 走看看