Leetcode 模式串匹配②

 

在Linux Shell命令下通配符'*'表示0个或多个字符,‘?’表示一个字符 现编写一段代码实现通配符'*'和'?'的功能。

 

输入描述:

第一行输入通配字符串
第二行输入要匹配查找的字符串

输出描述:

输出所有匹配的字串起始位置和长度,每行一个匹配输出
如果不匹配,则输出 -1 0
如果有多个按照起始位置和长度的正序输出。

示例1

输入

*.com
shopeemobile.com

输出

0 16
1 15
2 14
3 13
4 12
5 11
6 10
7 9
8 8
9 7
10 6
11 5
12 4

【思路】

关于通配符匹配,对于匹配串S1 和 模式串 T1  其基本思路是:

if(T[i]=='?' || T[i]==S[j])
  dp[i][j]=dp[i-1][j-1];
if(T[i]=='*')
  dp[i][j]=dp[i-1][j]||dp[i][j-1]; 

但本题有所不同,需要找出所有可以匹配的位置

采取枚举匹配串方式,时间复杂度很大

 

基本策略:

枚举源匹配串的起点,由 枚举点开始的串 和 模式串 做匹配计算

 

采取搜索的策略:

DFS(int i,int j) 表示当前研究的是  匹配串i位置 模式串的j位置   那么:

  • 若j==t.length()  =》 那么模式串搜索完毕=》符合要求填入结果=》return
  • 若i==s.length() =》 那么匹配串搜索完毕 =》return
  • 若s[i]==t[j] 或者 t[j]=='?' =>搜索下一组位置 DFS(i+1,j+1)
  • 若t[j]=='*'  那么搜索  DFS(i+1,j)  以及  DFS(i,j+1)
  • 否则 s[i]!=t[j]  那么直接返回

 

该方法和采取动态规划方法对比? 采取传统动态规划,空间超

该方法空间开销更小,并且由于中间有及时剪切,即如果可以判断一定无法匹配,那么及时返回

剪切点:

初始化进入 DFS时,发生在当且仅当下列三种情况:

s[0]==t[0]  两者第一个字母相等时=>可进入搜索
t[0]=='?'   模式串第一个字母为? =>可进入搜索
t[0]=='*'   模式串第一个字母为* =>可进入搜索

具体代码实现:

string s, t;
set<int> S;  //存放结果
//从待匹配串i开始  模式串j开始 dfs 
void DFS(int i, int j) {
    if (j == t.length())  //模式串搜索到最后节点 那么搜索成功
    {
        S.insert(i);
        return;
    }
    if (i == s.length())
        return;
    if (s[i] == t[j] || t[j]=='?')      //两者相等  那么往后
        DFS(i + 1, j + 1);
    else if ( t[j] == '*')   //如果模式串 当前节点为*
    {
        DFS(i, j + 1);      //那么有种搜索方向 
        DFS(i + 1, j);
    }
}
int main() {
    cin >> t >> s;
    bool flag = false;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == t[0] || t[0] == '*' ||t[0]=='?')  //根据两者首字母判断是否进入DFS搜索
        {
            DFS(i, 0);
            if (!S.empty())
            {
                flag = true;
                for (auto item:S)
                        cout << i << " " <<item - i << endl;
            }
            S.clear();
        }
    }
    if (!flag)
        cout << -1 << " " << 0 << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值