题目:通配符匹配
描述:请实现支持'?'and'*'.的通配符模式匹配
'?'可以匹配任何单个字符。
'*'可以匹配任何字符序列(包括空序列)。
返回两个字符串是否匹配
函数声明为:bool isMatch(const char *s, const char *p)
下面给出一些样例:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "d*a*b") → false
示例1:输入:"ab","?*",返回值:true
解法一:
思路分析:通过题目分析我们可以大致了解题目的意思,主要是比较两个字符串是否相等,但是还包括两个通配字符,'?'表示可以匹配任何单个字符,'*'可以匹配任何字符序列(包括空序列),已知两个字符串指针:*s和*p,设定两个存储位置的指针变量char* spd主要用于存储S指针的位置和char* ppd用于存储p指针的位置,主要分为三种情况:
其一为,当s指针指向的字符与p指针指向的字符相等或者p指针为“?”代表两个字符匹配,直接进行下一轮的判断。比如"a", "?",这两个字符串相等。
其二为,当p指针为“*”时,为这道题的重点,也就是可以匹配任何字符序列(包括空序列),这时候,我们就需要spd和ppd记录s和p指针的位置,然后通过设定的标记位进行循环判断。比如"aa", "*"返回true。
其三为,当两个字符串的值不相等时,可以直接返回false。比如"a","b"。
实例分析:输入:"ab","?*"
第一次判断:因为s和p指针指向的内容分别为,a和?,所以可以进行下一次的判断。
输入 | ab | ?* |
| 第一个指针指向字符相等,下一次 |
第二次判断:当p为*时,就需要进行考虑了,因为不知道后面是否还存在字符,所以将s的字符位置赋给spd用于保存,将p指针的下一位赋给ppd,同样用于保存,(因为这一位*在这一次已经在进行考虑了),同时设置标记位为1。
输入 | b | * |
| *可以匹配任何序列,所以需要判断当标记位为1时,需要将s的指针指向下一位,将ppd中的字符内容翻出来,然后再进行下一轮的比较 |
第三次:最终输出true。
实例二:"aab","a*b"
第一次判断:因为s和p指针指向的内容分别为,a和a,所以可以进行下一次的判断。
输入 | aab | a*b |
| 第一个指针指向字符相等,下一次 |
第二次判断:当p为*时,开始进行考虑,将s的字符位置ab赋给spd用于保存,将p指针的下一位b赋给ppd,同样用于保存,同时设置标记位为1。执行标记位程序,将s指向下一位,p指针指向ppd中的内容。
输入 | ab | *b |
| *可以匹配任何序列,标记位为1 |
第三次判断:执行第一条程序判断值相同。
输入 | b | b |
| 和第一次相同,所以返回true |
在程序的尾端我们应该注意的一点是,当s指针指向空时,p指针指向“*”的话,还是需要将p指针指向下一位,因为我们最后返回的值为!*p。
具体C程序为:
/** * * @param s string字符串 * @param p string字符串 * @return bool布尔型 */ int isMatch(char* s, char* p ) { // write code here char* spd;//设置指针,主要用于存储S指针的字符 char* ppd;//存储p指针的字符 int specil = 0;//标记为 while(*s){ if(*s == *p || *p == '?'){//当两个指针指向相等或者是p指针所指字符位通配符?时 s++;//判断下一位 p++;//判断下一位 } else if(*p == '*'){ spd = s;//将s中的字符位置赋给spd ppd = ++p;//p走向下一位,记录当前位置的值 specil = 1;//标记为设置位1 } else if(specil){ s = ++spd;//s可以与*匹配 p = ppd;//返回p的位置值 } else{ return 0; } } while(*p == '*'){//监测空字符 p++; } return !*p; }
因为该程序循环的是s的全部字符,故时间复杂度为O(N),N为s的长度,M为p的长度,当p的字符串长度大于s的字符串长度时,时间复杂度为O(M),空间复杂度为O(N + M)。
解法二:
思路分析:我们通过上面分析可以得到一个基本的困惑就是,当发生通配符“*”匹配时应该是这道题最难的点,所以我们在第二种方法中从最简单的套路开始考虑,首先判断p的第一个元素是否为*,如果是的话,将问题转换为考虑该*匹配多少次的问题了,也就是判断isMatch(s[1:],p)和isMatch(s,p[1:]),如果p的第一个元素不是*的话,我们只要判断s[0]与p[0]能否匹配即可,我们用python进行编写。
Python代码为:
# # # @param s string字符串 # @param p string字符串 # @return bool布尔型 # class Solution: def isMatch(self , s , p ): # write code here s_len, p_len = len(s), len(p)#输出这两个字符串的长度 mem = [[False]*(p_len + 1) for _ in range(s_len + 1)]##循环创建一个Plen+1为行和Slen+1为列的表格 mem[0][0] = True#设置第一个元素为true for i in range(s_len + 1):#循环判断 for j in range(1, p_len + 1): if p[j-1] == '*':#当为*的时候,考虑应该匹配多少次 mem[i][j] = mem[i][j-1]&nbs***bsp;(i > 0 and mem[i-1][j]) else:#当不为#的时候考虑指针对应的值是否相等,以及另一个通配符“?”的情况 mem[i][j] = i > 0 and mem[i-1][j-1] and (s[i-1] == p[j-1]&nbs***bsp;p[j-1] == "?") return mem[-1][-1]
for循环存在循环Slen与Plen的情况,故其时间复杂度为O(N^2),其中N为字符串s或者p的长度,设置了一个二维数组用于存放bool类型,故空间复杂度为O(N^2)。