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
双指针法
复杂度
时间 O(N) 空间 O(1)
思路
假设我们用两个指针分别指向s和p字符串中要匹配的位置,首先分析下通配符匹配过程中会有哪些情况是成功:
-
s的字符和p的字符相等
-
p中的字符是
?
,这时无论s的字符是什么都可以匹配一个 -
p中遇到了一个
*
,这时无论s的字符是什么都没关系 -
s已经匹配完,但是p后面还有很多连续的`*
-
当在某一位置p和s不匹配时,我们可以从
*
后面开始匹配,即p.start=start+1;
这里1和2的情况比较好处理,关键在于如何处理3和4的情况。当我们遇到一个*
时,因为之后可能要退回至该位置重新匹配,我们要将它的下标记录下来,比如idxstar
。但是,当我们连续遇到两次4的情况,如何保证我还是能继续匹配s,而不是每次都退回idxstar+1
导致循环呢?所以我们还要记录一个idxmatch
,用来记录用上一个*
连续匹配到的s中的下标。最后,对于情况5,我们用一个循环跳过末尾的*
跳过就行了。
代码
public class Solution {
public boolean isMatch(String s, String p) {
int idxs = 0, idxp = 0, idxstar = -1, idxmatch = 0;
while(idxs < s.length()){
// 当两个指针指向完全相同的字符时,或者p中遇到的是?时
if(idxp < p.length() && (s.charAt(idxs) == p.charAt(idxp) || p.charAt(idxp) == '?')){
idxp++;
idxs++;
// 如果字符不同也没有?,但在p中遇到是*时,我们记录下*的位置,但不改变s的指针
} else if(idxp < p.length() && p.charAt(idxp)=='*'){
idxstar = idxp;
idxp++;
//遇到*后,我们用idxmatch来记录*匹配到的s字符串的位置,和不用*匹配到的s字符串位置相区分
idxmatch = idxs;
// 如果字符不同也没有?,p指向的也不是*,但之前已经遇到*的话,我们可以从idxmatch继续匹配任意字符
} else if(idxstar != -1){
// 用上一个*来匹配,那我们p的指针也应该退回至上一个*的后面
idxp = idxstar + 1;
// 用*匹配到的位置递增
idxmatch++;
// s的指针退回至用*匹配到位置
idxs = idxmatch;
} else {
return false;
}
}
// 因为1个*能匹配无限序列,如果p末尾有多个*,我们都要跳过
while(idxp < p.length() && p.charAt(idxp) == '*'){
idxp++;
}
// 如果p匹配完了,说明匹配成功
return idxp == p.length();
}
}
字符串匹配之BF算法
BF(Brute Force)算法是模式匹配中最简单最直观的算法, 其基本思想是从主串T(t0,t1,t2,t3…t(n-1))中的第start个自字符起和模式P的第一个字符进行比较, 如果相等, 则继续比较后续字符; 如果不相等, 则回溯至主串中的第start+1个字符位置继续和模式P进行比较. 以此类推, 直到模式P中每个字符都和主串T中的一个连续字符序列完全相同, 则匹配成功, 否则,匹配失败.
BF算法是一种蛮力算法, 其特点是简单直观, 但由于涉及到多次回溯, 算法效率很低. 不适用于信息量较大的情况.
下面给出BF的一个实现如下:
//
// main.cpp
// BF
//
// Created by Scarecrow on 16/12/7.
// Copyright © 2016年 XB. All rights reserved.
//
#include <iostream>
using namespace std;
#define NO_MATCH -1
#define LEN_ERROR -2
/**
字符串模式匹配之BF算法
@param t 主串
@param p 模式(子串)
@param start 起始匹配索引(t)
@return 匹配结果
*/
int bruteForce(char const t[], char const p[], int const start)
{
size_t len_t = strlen(t);
size_t len_p = strlen(p);
//如果要匹配的子串长度大于主串长度
if (len_t < len_p) {
return LEN_ERROR;
}
int index_t = start;
int index_p = 0;
while (index_p < len_p && index_t < len_t) {
if (t[index_t] == p[index_p]) {
++index_p;
++index_t;
}else{
index_t = index_t - index_p + 1;
index_p = 0;
}
}
if (index_p >= len_p) {
return index_t - index_p;
}
return NO_MATCH;
}
int main(int argc, const char * argv[]) {
char p[] = "fe";
char t[] = "feherrrfe";
int start = 3;
int index = bruteForce(t, p, start);
cout << index << endl;
return 0;
}