1. 程式人生 > >[leetcode] Wildcard matching——程式設計菜鳥們絕對值得一看

[leetcode] Wildcard matching——程式設計菜鳥們絕對值得一看

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
class Solution {
public:
	bool isMatch(const char *s, const char *p) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		int i , j, k;
		int lengths,lengthp;
		i=j=k=lengths=lengthp=0;
		lengths=strlen(s);
		lengthp=strlen(p);
		if(lengths==0 && lengthp==0)
			return true;
		if(lengthp==1){
			if(*p=='*')
				return true;
			else if(*p=='?'){
				if(lengths==1)
					return true;
				else
					return false;
			}
			else{
				if(lengths==1)
					return *s==*p;
				else
					return false;
			}

		}else{
			if(*p=='?')
				return isMatch(++s,++p);
			else if(*p=='*'){
				for(j=0 ; j<lengthp ; j++){
					k|=isMatch(s+j,++p);
				}
				return k;
			}
			else{
				if(*s==*p)
					return isMatch(++s,++p);
				else
					return false;
			}
		}
	}
};

上面這個遞迴是我自己寫的,思路很簡單了,主要分為以下幾個關鍵的部分:

1. 當遇到?時,那麼可以匹配任意的源字串中的一個字元,我們只需遞迴的匹配下一個萬用字元串和下一個源字串。
2. 當遇到*時,那麼可以匹配任意的源字串,那麼我們就從0個字元開始遞迴匹配。
3. 最簡單的是普通字元,那麼直接匹配,再匹配下面的字串。

發現一個不錯的連結:

這裡面介紹了一些不錯的萬用字元匹配的演算法,看了看他寫的比我好多了!!!自己的程式碼確實跟屎一樣。然後我就稍微把他的程式碼更改了一下,他似乎是一個極其熱愛和平的人,哈哈哈哈:

class Solution {
public:
    bool isMatch(const char *s, const char *p) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		while(*p){
			switch(*p){
				case '?':
//					if(*s=='')
				if(*s)return isMatch(++s,++p);
				else return false;
				break;
				case '*':
					for(p++;*p!='*';p++);
					if(!*p)return true;
					while(*s)if(isMatch(s++,p))return true;
					return false;
				default:
					if(*s!=*p)return false;
					break;
			}
			p++,s++;
		}
		for(;*p=='*';p++);
		return ((!*p)&&(!*s));
	}
};

這程式碼用到了遞迴,是不能通過大資料的。當然如果你認為這種程式碼就已經夠簡潔的話那你就圖樣圖森破了。程式碼可以簡潔到下面這個樣子:

class Solution {
public:
	bool isMatch(const char *s, const char *p) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		switch(*p){
			case '\0':
				return !*s;
			case '*':
				return isMatch(s,p+1) || *s && isMatch(s+1,p);
			case '?':
				return *s && isMatch(s+1,p+1);
			default:
				return (*s==*p) && isMatch(s+1,p+1);
		}
	}
};

上面的都是遞迴的解法,遞迴的解法效率永遠是硬傷!下面介紹非遞迴的解法:

class Solution {
public:
    bool isMatch(const char *s, const char *p) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		int i,star;
	new_segment:
		star=0;
		if(*p=='*'){
			star=1;
			for(p++;*p=='*';p++);
		}
	test_match:
		for(i=0 ; p[i] && (p[i]!='*');i++){
			if(s[i]!=p[i]){
				if(!s[i])return false;
				if((p[i]=='?') && s[i]) continue;
				if(!star)return false;
				s++;
				goto test_match;
			}		
		}
		if(p[i]=='*'){
			s+=i;
			p+=i;
			goto new_segment;
		}
		if(!s[i])return true;
		if(i && p[i-1]=='*') return true;
		if(!star) return false;
		s++;
		goto test_match;
	}
};

這裡面用到了goto語句,我會考慮將goto去除的