LeetCode题目:44. Wildcard Matching

LeetCode题目:44. Wildcard Matching

原题链接:https://leetcode.com/problems/wildcard-matching/description/

解题思路:

核心思想:

由题可知,’*’意思是匹配认可,因此,多个连续的’*’组成的字符串和单个’*’的意义一样,因此,可以把输入子串s根据’*’分割,变成字符串数组ss.

字符串数组分为三部分:

  1. 首位字符串ss[0]:如果输入字符串不以’*’开头,则首位字符串必须要与母串的开头匹配.
  2. 末尾字符串ss[length-1]:如果输入字符串不以’*’结束,则末尾字符串必须要与母串的末尾匹配.
  3. 其他字符串:其他字符串只要母串的子串即可,但是必须要按照顺序,即ss[1]的匹配位置必须要比ss[2]的匹配位置小.

因此,该题在字符串分割成字符串数组,并先将首位字符串和末尾字符串的特殊情况解决后,就变成了一个贪心问题,(很明显,对每一个数组中的字符串,匹配的位置最前,匹配成功的可能性就越大)因此,我们可以用贪心算法解决.

步骤如下:

  1. 将输入子串s根据’*’分割成字符串数组ss

  2. 若s[0]不为’*’,将ss[0]与母串p的开头匹配,若匹配成功,则在数组中移除ss[0],p移除相应部分

  3. 若s[length-1]不为’*’,将ss[length-1]与母串p的结尾匹配,若匹配成功,则在数组中移除ss[length-1],p移除相应部分

  4. i从0->n-1遍历数组,将字符串ss[i]与p匹配,并找到第一个匹配位置:

    ​ 如果匹配成功,p移除匹配部分和匹配之前的部分,只留下匹配之后的部分

  5. 如果字符串数组中的全部字符串都匹配成功,则返回true,否则返回false

代码细节:

  1. c++中并没有split函数,需要自己去实现
  2. 字符串匹配时,需要注意’?’可以代替任何字符

坑点:

  1. 此题和第10题Regular Expression Matching类似.但是由于此题数据量大,用递归的方法会超出时间,因此改用迭代.
  2. 需要注意”“和”*”.
  3. 若子串没有包含’*’,则就是正常匹配.

代码:

#include <cstring>
#include <string>
bool isEqual(char a, char b) {
    return a == b || b == '?' || a == '?';
}

bool isEqual(string a, string b) {
    if (a.length() != b.length())  return false;
    for (int i = 0; i < a.length(); i ++)
        if (!isEqual(a[i], b[i]))  return false;
    return true;
}

int subStr(string s, string b, int pos = 0) {
    for (int j = pos; j <= int(s.size() - b.size()); j++) {
        int k;
        for (k = 0; k < b.length(); k++)
            if (!isEqual(b[k], s[j + k]))  break;
        if (k == b.length())  return j;
    }
    return -1;
}

// 切割字符串
vector<string> split(string& str,const char* c)
{
    char *cstr, *p;
    vector<string> res;
    cstr = new char[str.size()+1];
    strcpy(cstr,str.c_str());
    p = strtok(cstr,c);
    while(p!=NULL)
    {
        res.push_back(p);
        p = strtok(NULL,c);
    }
    return res;
}

bool isMatch(string s, string p) {
    // 没有*的情况
    if (p.find('*') == -1)  return isEqual(s, p);

    vector<string> splitStrs = split(p, "*");  // 将字符串根据*分割

    // 第一个固定,没有*
    if (p[0] != '*') {
        string firstStr = splitStrs.front();
        splitStrs.erase(splitStrs.begin());

        // 判断头部是否相等
        if (s.length() < firstStr.length() ||
            !isEqual(s.substr(0, firstStr.length()), firstStr))  return false;
        s.erase(0, firstStr.length());
    }

    // 最后一个固定,没有*
    if (p[p.length() - 1] != '*') {
        string endStr = splitStrs.back();
        splitStrs.pop_back();

        // 判断尾部是否相等
        if (s.length() < endStr.length() ||
            !isEqual(s.substr(s.length() - endStr.length(), endStr.length()), endStr))  return false;
        s.erase(s.length() - endStr.length(), endStr.length());
    }

    int pos = 0;
    for (int i = 0; i < splitStrs.size(); i++) {
        // 可由贪心,寻找第一个子串
        pos = subStr(s, splitStrs[i], pos);

        // 如果之后不存在子串匹配,直接退出
        if (pos == -1)  return false;
        pos += splitStrs[i].length();
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值