通配符匹配

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字符串中要匹配的位置,首先分析下通配符匹配过程中会有哪些情况是成功:

  1. s的字符和p的字符相等

  2. p中的字符是?,这时无论s的字符是什么都可以匹配一个

  3. p中遇到了一个*,这时无论s的字符是什么都没关系

  4. s已经匹配完,但是p后面还有很多连续的`*

  5. 当在某一位置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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值