leetcode44 wildcard matching递推方法+trick方法

通配符匹配。简单来说就是判断字符串s和pattern字符串p是否匹配,p中的?符号表示任意一个字符,p中的*符号表示任意一个字符序列。

首先说说我自己的递推的思想:

虽然很多人说这种是动态规划的解法,但我本人并不认同这种说法,如果严格按照动态规划的定义划分的话,这个既没有最优子结构也没有重复计算的问题。不过不用在意这些细节了。

设一个二维数组bp,bp[i][j]的语义是:s的前i个字符和p的前j个字符是否匹配。

边界条件b[0][0]=true,b[0][j]=true(p的前j个字符都是*)

我们可以求解bp[i][j]:

如果p[j]是字母,则bp[i][j]=(p[j-1]==s[i-1]) && bp[i-1][j-1]

如果p[j]是?,则p[j]匹配任意一个字符,bp[i][j]=bp[i-1][j-1]

如果p[j]是*,如果*代表0个字符的话,则bp[i][j]=b[i][j-1],如果*代表多个字符的话,则s的前i个字符和p的前j个字符是否匹配,取决于s的前i-1个字符和p的前j个字符是否匹配。如果b[i-1][j]=true,则b[i][j]=true,此时即*代表的字符序列增加了一个字符s[i]而已。所以bp[i][j]=bp[i-1][j] || bp[i][j-1]

求解代码:(其实核心代码就几行,剩下的都是一些分配数组内存、释放内存、初始化之类的东西)

#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
	bool **bp;
	//bp[i][j]:whether the first i characters of s and the first j characters of p match
    bool isMatch(string s, string p) {
		if(s.size()==0){
			if(p.size()!=0){
				for(int i=0;i<p.size();++i){
					if(p[i]!='*') return false;
				}
				return true;
			}else{
				return true;
			}
		}else if(p.size()==0) return false;
		
		//cout<<"s="<<s<<"  p="<<p<<endl;
		
        init(s.size(),p.size());
		
		//edge value
		bp[0][0]=true;
		unsigned int tmp=1;
		for(;tmp<=p.size();++tmp){
			if(p[tmp-1]!='*') break;
			bp[0][tmp]=true;
		}
		for(;tmp<=p.size();++tmp) bp[0][tmp]=false;
		
		for(unsigned int i=1;i<=s.size();++i){
			for(unsigned int j=1;j<=p.size();++j){
				if(p[j-1]=='?') bp[i][j]=bp[i-1][j-1];
				else if(p[j-1]!='*') bp[i][j]=(p[j-1]==s[i-1]) && bp[i-1][j-1];
				else bp[i][j]=bp[i-1][j] || bp[i][j-1];
			}
		}
		
		bool ret=bp[s.size()][p.size()];
		
		//cout<<"3 bp="<<endl;
		//for(unsigned int i=0;i<=s.size();++i){
			//for(unsigned int j=0;j<=p.size();++j){
				//cout<<bp[i][j]<<" ";
			//}
			//cout<<endl;
		//}
		
		//cout<<"ret="<<ret<<endl;
		finish(s.size());
		return ret;
    }
	void init(unsigned int s_size,unsigned int p_size);
	void finish(unsigned int s_size);
};

void Solution::finish(unsigned int s_size){
	for(unsigned int i=0;i<=s_size;++i) delete []bp[i];
	delete []bp;
}

void Solution::init(unsigned int s_size,unsigned int p_size){
	bp=new bool*[s_size+1];
	for(unsigned int i=0;i<=s_size;++i){
		bp[i]=new bool[p_size+1];
	}
	for(unsigned int i=0;i<=s_size;++i){
		for(unsigned int j=0;j<=p_size;++j) bp[i][j]=false;
	}
}

后来在网上看到一篇线性时间复杂度的解法。但是这种解法我觉得属于trick的解法了,不具备通用性。不管怎样也先记录下来吧:

我们以s="abcdcdef"   p="ab*cdef"为例来说明

设i1为s的下标指针,i2为p的下标指针,初始i1=i2=0

1、s[i1]=p[i2],所以++i1,++i2

2、p[i2]=*,所以ss=i1,star=i2(star记录星号的位置,s[0]~s[ss]和p[0]~p[star]匹配,此时star所在的星号代表0个字符),i2=star+1,  ++i1(继续判断i1和i2是否匹配)

3、s[i1]=p[i2],所以++i1,++i2

4、s[i1]=p[i2],所以++i1,++i2

5、s[i1]和p[i2]不匹配,所以当star位置的星号代表0个字符的时候无法匹配,所以下一步尝试star位置的星号代表一个字符。++ss,i1=ss+1,i2=star+1

6、s[i1]和p[i2]不匹配,所以当star位置的星号代表一个字符的时候也无法匹配,所以下一步尝试star位置的星号代表两个字符。++ss,i1=ss+1,i2=star+1。此时匹配。

大致就是这个思路,我根据这个求解的思路写的程序:

#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    bool isMatch(string s, string p) {
		unsigned int ss=0;
		int star=-1;
		unsigned int i1=0,i2=0;
		while(i1<s.size()){
			
			if(i2<p.size() && (p[i2]==s[i1]||p[i2]=='?')){
				++i1;
				++i2;
				continue;
			}
			
			if(i2<p.size() && p[i2]=='*'){
				ss=i1-1;
				star=i2++;
				continue;
			}
			
			if(star!=-1){
				i2=star+1;
				++ss;
				i1=ss+1;
			}else{
				return false;
			}
		}
		//cout<<"i1="<<i1<<"  i2="<<i2<<endl;
		for(;i2<p.size() && p[i2]=='*';++i2);
		return i2==p.size()?true:false;
    }
};

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值