【LeetCode】44. Wildcard Matching解法及注释

44. Wildcard Matching

Implement wildcard pattern matching with support for '?' and '*'.
1. '?' Matches any single character.
2. '*' Matches any sequence of characters (including the empty sequence).
3. The matching should cover the entire input string (not partial).
4. The function prototype should be: bool isMatch(const char *s, const char *p)
<Some examples:>
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false

【分析】

此题是一个“通配符”匹配问题,给定两个字符串,判断是否匹配,根据题意:字符串s为不包含通配符的普通字符串,字符串p为包含通配符“*”和“?”的字符串,我们需要判断的就是字符串p是否与s匹配,因此,我们需要逐次比较两个字符串的字符。

根据题目给出的examples,我们可以得出一些基本规则:(设ps,pp分别为字符串s和p的下标)

1. 如果s[ps]==p[pp],直接移动下标(pp++;ps++),比较下一个位置的字符是否相等;

2. 如果p[pp]=='?',那么无论对应的s[ps]是什么字符都为所谓,同1的处理一样;

3. 如果p[pp]==‘*’,本题的难点就来了,‘*’可以匹配任何字符和字符串,但它究竟该和s中的哪些或哪些字符匹配,我们需要比较后面的字符,举个例子s="abcacc",p="abc*c",前三个字符都是匹配的,移动下标即可,当ps=pp=3,即s[ps]='a',p[pp]='*'时,我们并不知道‘*’该匹配什么字符,只能根据后面的比较结果来决定,我们移动pp到下一位:p[4]='c',与s[3]不匹配,因此,‘*’需要匹配s[3],即使确定s[3]由p[3]匹配,我们并不能确定p[3]='*'只与s[3]匹配,它可以匹配多个字符,因此我们需要保存‘*’的位置。我们继续移动ps,s[ps]=s[4]='c',此时pp回到为3,同上,我们移动pp,p[pp]=p[4]='c',两者恰好匹配,同时移动pp,ps,发现s[5]!=p[5],这时候,我们需要用到“回溯法”的思想,重新将pp移动到‘*‘的位置3,ps回溯到上一次已经用’*‘匹配过的ps=3的位置的下一位,用pp=3中的’*‘继续匹配ps=4位置的字符,再移动ps。s[ps]=s[5]与p[pp]=p[3]比较,p[3]='*',移动pp,比较下一位,发现p[4]=s[5],同时移动pp,ps,达到字符串s的末尾,循环比较结束。

4. 循环比较结束后,并不能确定p和s匹配,比如s="abcacc",p="abc*cd",我们需要对p进行验证,只有pp同时到达字符串尾端或者p后面剩余的字符全为’*‘如:s="abcacc",p="abc********",才能形成匹配。

【算法及注释】

class Solution {
public:
   bool isMatch(string s,string p)
	{
		int LS,LP;//求输入字符串的长度,以便特殊情况的处理
		LS=s.length();
		LP=p.length();

		if(LS==0&&LP==0)return true;//均为空串,返回true
		else if(LS==0&&LP!=0)//s为空,p中全部为'*'则匹配,返回true,否则返回false
		{
			int i=0;
			while(p[i]=='*')i++;
			if(i==LP)return true;//判断p 中是否全部为'*'
			else return false;
		}
		else
		{
			int pp,ps;//记录输入字符串的下标
			pp=ps=0;//初始化
			int matchIndex=0;//记录待匹配字符的下标
			int starIndex=0;//记录上一个'*'出现的下标
			bool flag=false;//标记是否前面出现过'*'
			while(ps<LS)//循环控制条件,因为我们是用p去匹配s,因此循环以s为主导,p主动去匹配s
			{
				if(s[ps]==p[pp]||p[pp]=='?')//最简单的情况,直接移动下标,比较下一位
				{
					pp++;
					ps++;
				}
				else if(p[pp]=='*')//出现'*'
				{
					flag=true;//标记'*'出现
					starIndex=pp;//记录‘*’出现的位置下标
					matchIndex=ps;//记录待匹配S字符串的字符下标
					pp++;//这时只移动pp,再与s中的字符比较,从而确定前面的'*'如何匹配
				}
				else
				{
					if(!flag)return false;//如果对应位置的字符不同,前面也没有出现过'*',说明两者不匹配,返回
					pp=starIndex;//如果前面出现'*',将pp“回溯”到'*'出现的位置
					ps=matchIndex;//ps“回溯”到上一次待匹配的字符的下标,进行匹配
					ps++;//待匹配的s中的字符匹配后,移动ps到下一个位置,继续判断
				}
			}
			while(p[pp]=='*'&&pp<LP)pp++;//待s中的字符被完全匹配后,再对p中的后续字符进行检验,到达末尾或者后面全为'*'
			if(p[pp]=='\0')return true;
			else return false;
					
		}	
	}
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jin_Kwok

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值