LeetCode Wildcard Matching 优化动态规划法和迭代算法

原创 2013年12月07日 08:26:53

Implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

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

 实现通配符的功能。特殊的串匹配。这道题的迭代法会更加简单,运行速度更加快。还是相当有难度的题目。
 参考了Leetcode上的程序,然后自己优化了一下。

 下面是动态规划法的优化程序:

优化地方:增加一个bool tream标志。如果当前行全部为false,那么就可以判断最终结果也为false。如果字符串很长,又是不匹配的话可以加快很多速度。

这样可以让速度提高差不多100ms,有图:

原算法是300多ms,我修改之后就变为200多ms了。

修改:

vector<vector<bool> > r(2, vector<bool>(ms_max, false));

修正为

vector<vector<bool> > r(2, vector<bool>(ms_max+1, false));

参考程序:http://discuss.leetcode.com/questions/222/wildcard-matching

bool isMatch(const char *s, const char *p) {
		if (!*s && !*p) return true;

		int ms_max = 1;//size of *s
		const char* ss = s;
		while(*ss){ ++ms_max;++ss;}//ms_max = strlen(s)+1;
		int np_max = 1;
		const char* pp = p;
		while(*pp){if(*pp!='*')++np_max;++pp;}//计算不带非*的字符长度+1
		if(ms_max < np_max) return false;
		//这里写vector<bool>(ms_max, false)居然Leetcode上AC了
		//但是在vs上是下标溢出的,正确应该+1.
		vector<vector<bool> > r(2, vector<bool>(ms_max+1, false));
		bool flag = 1;
		r[0][0] = true;//最右上角初始化为true
		do{//*p
			//增加标志,提前判断匹配串,返回;当前行全部false,结果肯定false
			bool tream = false;
			int ms = 1;
			ss = s;//每次从表的1的位置开始填表
			if (*p == '*'){//3.
				while(*p == '*') ++p;//处理掉重复的*
				--p;//返回填表位置
				//因为*可以和空""匹配,所有把当前行0列置真
				r[flag][0] = r[!flag][0];//例如特殊情况:"aa", "*"
				for( ;ms <= ms_max; ++ms){//up and left判断两格就可以了,没有所有格都判断
					if (r[!flag][ms] || r[flag][ms-1])//这里没有从0开始
					{
						tream = true;
						break;
					}
					else r[flag][ms] = false;
				}
				for(;ms <= ms_max; ++ms){
					r[flag][ms] = true;
				}
			}
			else{
				do{//填写行
					bool r_flag = false;//1.
					if (*ss == *p || *p == '?'){//2.
						r_flag = r[!flag][ms-1];//diagnal
					}
					r[flag][ms]=r_flag;
					if (r_flag) tream = true;
					++ms;++ss;
				}while(*ss);//*s
				r[flag][0] = false;//第二行开始的最右边格填false
			}
			if (tream == false) return false;
			++p;
			flag = !flag;//利用flag来交替使用两个数组代表一个二维表
		}while(*p);
		return r[!flag][ms_max-1];
	}


 下面是迭代程序,要熟悉这个思维:记录上一次开始比较的位置,如图:

 下面程序是直接使用指针记录位置

bool isMatch(const char *s, const char *p) {
		const char *backtrack_s = NULL, *backtrack_s = NULL;
		while (*s) {
			if (*p == '?' || *s == *p) {
				++s;
				++p;
			}
			else {
				if (*p == '*') {
					while (*p == '*')
						++p;
					if (*p == '\0') 
						return true;
					backtrack_s = s;
					backtrack_s = p;
				}
				else {//backtrack_s是为了判断是否到尾,注意:还有判断是否出现了*
					if (backtrack_s) {
//注意:在当前位置往后判断出现不相等的时候,再重新回到下一个位置重新往后比较
						s = ++backtrack_s;
						p = backtrack_s;//恢复p的位置
					}
					//s的恢复位置backtrack_s已经试完,那么就不匹配
					else return false;
				}
			}
		}
		while (*p == '*')//处理p末端的*
			++p;
		return (*s == '\0' && *p == '\0');
	}
};

 

//2014-2-24 update AC
	bool isMatch(const char *s, const char *p) 
	{
		int sn = strlen(s);
		int pn = strlen(p);
		for (int i = 0, c = 0; i < pn; i++)
		{
			if (p[i] != '*') c++;
			if (c > sn) return false;
		}
		vector<vector<bool> > tbl(2, vector<bool>(sn+1));
		tbl[0][0] = true;
		bool idx = true;
		bool finished = false;
		for (int i = 0; i < pn && !finished; i++)
		{
			if (p[i] == '*')
			{
				while (i < pn && p[i] == '*') i++;
				i--;
			}
			finished = true;
			if (p[i] == '*')
			{
				int j = 0;
				for (; j < sn && !tbl[!idx][j]; j++) tbl[idx][j] = false;
				if (j <= sn) finished = false;
				for (; j <= sn; j++) tbl[idx][j] = true;
			}
			else
			{
				tbl[idx][0] = false;
				int j = 0;
				for ( ; j < sn; j++)
				{
					if (s[j] == p[i] || p[i] == '?') 
						tbl[idx][j+1] = tbl[!idx][j];
					else tbl[idx][j+1] = false;
					if (tbl[idx][j+1]) finished = false;
				}
			}
			idx = !idx;
		}
		return finished? false : tbl[!idx][sn];
	}

好像增加和不增加一个结束标志,其实效率也没多大影响。

本题关键的一个考点:判断p字符串中的总长字符减去*号数,得到的总长是否长于s字符串,如果长过,那么就返回假。


 

版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/,未经本作者允许不得转载。

LeetCode Wildcard Matching DP/贪心

这道题按理来说应该是Regular Expression Matching的简单版,但是测试数据较多较复杂,用普通的dfs会超时,常规dp会超内存,因此需要进行额外的处理。 方法一:DP 常规DP使...
  • ww32zz
  • ww32zz
  • 2015年12月19日 22:09
  • 391

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

动态规划(算法分析与设计)

1.矩阵连乘问题 参考博客:http://blog.sina.com.cn/s/blog_64018c250100s123.html a.i*k型号的矩阵与k*j型号的矩阵相乘,乘法次数为i*k*j ...

【LeetCode】Wildcard Matching 串匹配 动态规划

题目:Wildcard Matching /*LeetCode WildCard matching * 题目:给定一个目标串和一个匹配串,判定是否能够匹配 * 匹配串中的定义:字符————>字符...

Leetcode #44. Wildcard Matching 通配符匹配 解题报告

1 解题思想嗯,最近遇到要写Hard的频率偏高,而最近的重心也不再Leetcode上,心累。。Hard写起来都好麻烦。这道题好像之前也有几次,讲过类似的题目,也就是*能任意长度和字符匹配,?能匹配任意...
  • MebiuW
  • MebiuW
  • 2016年04月15日 23:16
  • 1379

【LeetCode】【C++】Wildcard Matching

题目‘?’ Matches any single character. ‘*’ Matches any sequence of characters (including the empty seq...

String、动态规划——wildcard-matching 通配符匹配

Implement wildcard pattern matching with support for'?'and'*'. '?' Matches any single character. '*'...

LeetCode --- 44. Wildcard Matching

题目链接:Multiply Strings Implement wildcard pattern matching with support for '?' and '*'. '?' Matc...
  • makuiyu
  • makuiyu
  • 2015年02月10日 08:58
  • 2601

44. Wildcard Matching

Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character....

林锐高质量编程中的几道面试题

内存的思考 在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”? C++语言支持函数重载,C 语言不支持函数重载。函数被C++编译后在库中的名字与C 语言的不同。假设...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:LeetCode Wildcard Matching 优化动态规划法和迭代算法
举报原因:
原因补充:

(最多只允许输入30个字)