首页 > 试题广场 >

实现字通配符*

[编程题]实现字通配符*
  • 热度指数:7723 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}在 Linux Shell 中,通配符 `*` 代表任意长度(可为 0的字符串。给定:
\hspace{23pt}\bullet\, 一条模式串 `p`(仅包含可见字符及通配符 `*`,无其他元字符);
\hspace{23pt}\bullet\, 一条目标串 `s`(仅包含除通配符 `*` 以外的可见字符); 
\hspace{15pt}请输出 `s` 中所有与 `p` 匹配的子串的起始位置(从 0 开始计)及长度

\hspace{15pt}若不存在匹配,输出 `-1 0`。多组匹配按"起始位置升序,长度升序"排序输出。

\hspace{15pt}> `*` 可匹配空串;匹配不要求整个 `s`,只需匹配其任一连续子串。

输入描述:
\hspace{15pt}第一行:模式串 `p`  (长度不超过20)
\hspace{15pt}第二行:目标串 `s`  (长度不超过 10^3


输出描述:
\hspace{15pt}对每一个匹配子串输出 `匹配起始位置  匹配的长度`(空格分隔)一行;若无匹配输出 `-1 0`。
示例1

输入

shopee*.com
shopeemobile.com

输出

0 16

说明

0 起始位置,16长度
示例2

输入

*.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
示例3

输入

o*m
shopeemobile.com

输出

2 5
2 14
7 9
14 2

备注:
本题已于下方时间节点更新,请注意题解时效性:
1. 2025-12-25 原数据范围有误,已修正为 10^3,同时重造了数据;时间限制拓展为 2s,空间限制拓展为 256MB。
#include <bits/stdc++.h>
using namespace std;

string s, t;
set<int> S;

void DFS(int i, int j){
    if(j==t.length())
        S.insert(i);
    if(i==s.length())
        return;
    if(s[i]==t[j])
        DFS(i+1, j+1);
    else if(t[j]=='*'){
        DFS(i, j+1);
        DFS(i+1, j);
        DFS(i+1, j+1);
    }
    return;
}

int main(){
    cin>>t>>s;
    bool flag = false;
    for(int i=0;i<s.length();i++){
        if(s[i]==t[0] || t[0]=='*'){
            DFS(i, 0);
            if(!S.empty()){
                flag = true;
                for(set<int>::iterator it=S.begin();it!=S.end();it++)
                    if(*it>i)
                        cout<<i<<" "<<*it-i<<endl;
            }
            S.clear();
        }
    }
    if(!flag)
        cout<<-1<<" "<<0<<endl;
    return 0;
}

发表于 2020-01-15 01:29:52 回复(11)
c++抄的offer
#include<iostream>
#include<vector>
using namespace std;
int Core(string &str1, string &str2, int left, int right,int start, int len)
{
    int res = false;
    if(str1[left] == '\0')
    {
        cout << start << " " << len << endl; 
        return true;
    }
    if(str1[left] != '\0' && str2[right] == '\0') return false;
    //当通配字符不是*时候,判断两个个字符是否相等
    if(str1[left] != '*')
    {
        if(str1[left] != str2[right]) return false;
        else 
        {
           res = Core(str1, str2, left+1, right+1, start, len+1);
        }
    }
    //当通配字符是*时候,通配字符向后移动或者查找字符向后移动
    else
    {
        //这里要注意不能用||因为一旦第一个条件成立第二个条件不会被执行
        bool tem1 = Core(str1, str2, left+1, right, start, len) ;
        bool tem2 = Core(str1, str2, left, right+1,start, len+1);
        res = tem1||tem2;
            
    }
    return res;
}
int main()
{
    
    string str1;
    string str2;
    cin >> str1 >> str2;
    if(str1 == "*")
    {
        for(int i = 0; i < str2.size();i++)
        {
            for(int j = 1; j + i <= str2.size();j++)
            {
                cout << i << " " << j << endl;
            }
        }
        return 0;
    }
    bool res = false;
    for(int i = 0; i < str2.size();i++) 
    {
        if(Core(str1, str2, 0,i,i,0)) res = true;
    }
    if(!res) cout << -1 << " " << 0 << endl;
    return 0;
}

发表于 2019-08-04 15:28:22 回复(3)
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
 
public class Main {
    private static boolean match(String matchStr, String str, int matchIdx, int idx) {
        if (matchIdx == matchStr.length() && idx == str.length()) {
            return true;
        }
        if (idx >= str.length() && matchIdx < matchStr.length() && matchStr.charAt(matchIdx) == '*') {
            return match(matchStr, str, matchIdx + 1, idx);
        }
        if (matchIdx >= matchStr.length() || idx >= str.length()) {
            return false;
        }
        if (matchStr.charAt(matchIdx) != '*' && matchStr.charAt(matchIdx) != str.charAt(idx)) {
            return false;
        }
        boolean flag = false;
        if (matchStr.charAt(matchIdx) == '*') {
            flag = match(matchStr, str, matchIdx + 1, idx) || match(matchStr, str, matchIdx, idx + 1);
        }
        if (matchStr.charAt(matchIdx) == str.charAt(idx)) {
            flag |= match(matchStr, str, matchIdx + 1, idx + 1);
        }
        return flag;
    }
 
    private static List<Integer[]> getMatchPosAndLen(String matchStr, String str) {
        List<Integer[]> ans = new ArrayList<>();
        for (int i = 0; i < str.length(); ++i) {
            if (matchStr.charAt(0) != '*' && matchStr.charAt(0) != str.charAt(i)) {
                continue;
            }
            for (int j = i; j < str.length(); ++j) {
                if (matchStr.charAt(matchStr.length() - 1) != '*' && matchStr.charAt(matchStr.length() - 1) != str.charAt(j)) {
                    continue;
                }
                if (match(matchStr, str.substring(i, j + 1), 0, 0)) {
                    ans.add(new Integer[]{i, j - i + 1});
                }
            }
        }
        if (ans.size() == 0) {
            ans.add(new Integer[]{-1, 0});
        }
        return ans;
    }
 
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.next();
        List<Integer[]> list = getMatchPosAndLen(matchStr, str);
        for (Integer[] arr : list) {
            System.out.println(arr[0] + " " + arr[1]);
        }
 
    }
}
暴力加略微剪枝,过了!
发表于 2020-02-14 01:44:18 回复(3)
这应该是最简单的方法了,而且非常高效,用时33ms,占用15324KB
在HJ71我们可以学习到match的使用方法,这个地方使用match极大地减少了工作量
a = input()
panduan = list(a.split('*'))
b = input()
a,c,lenb = a.replace('*','.*'),[],len(b)
for i in range(len(panduan)):
    if not panduan[i] in b:
        print('-1 0')
        quit()
from re import match
for i in range(lenb):
    for j in range(i+1,lenb+1):
        k = b[i:j]
        d = f'{i} {j-i}'
        kd = [k,d]
        c.append(kd)
for i in c:
    pi = match(a,i[0])
    if pi:
        ans = pi.group()
        if ans == i[0]:
            print(i[1])
首先将a以*号分割成为几部分,如果这几部分有任意一部分不在b中,那么就直接输出-1 0并且quit,可以直接跳出整个程序,就没有必要再写else了,然后将a中的*换成一个点加*号,这是很重要的正则表达式,从re中导入match,取出b中所有的连续子串,这个方法是通用必会的,同时,将对应要输出的字符串提前加入到列表中,统一存到列表c中,然后对所有的连续子串,我们使用match去匹配,这里match的返回值有点奇怪,有可能为none,所以必须要使用if条件句,并且使用group去取出最后匹配的值,因为这里已经是分割成所有子串了,所以需要严格匹配子串本身,如果取出的值等于子串本身,我们直接输出之前准备好的字符串即可
发表于 2025-08-14 10:52:51 回复(0)
暴力居然也可以过??一开始做的时候都没敢往上写,看了评论区才试了下居然过了??
#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<math.h>
using namespace std;
bool check(string p,string s) {
    int len1=p.size();
    int len2=s.size();
    vector<vector<bool>> dp(len1+1,vector<bool>(len2+1,false)); //dp[i][j]表示p[0...i-1]和s[0...j-1]是否匹配
    dp[0][0]=true;
    for(int i=1;i<=len1;++i) {
        if(p[i-1]=='*')
            dp[i][0]=dp[i-1][0];
    }
    for(int i=1;i<=len1;++i) {
        for(int j=1;j<=len2;++j) {
            if(p[i-1]==s[j-1]) {
                dp[i][j]=dp[i-1][j-1];
            } else {
                if(p[i-1]=='*') {
                    dp[i][j]=dp[i-1][j] || dp[i][j-1];
                } else {
                    dp[i][j]=false;
                }
            }
        }
    }
    return dp[len1][len2];
}
int main()
{
    string p;
    cin>>p;
    string s;
    cin>>s;
    if(p.size()==0) {
        cout<<"-1 0"<<endl;
        return 0;
    }
    int len=s.size();
    if(p=="*") {
        for(int i=0;i<len;++i) {
            for(int j=1;i+j<=len;++j) {
                cout<<i<<" "<<j<<endl;
            }
        }
        return 0;
    }
    bool flag=false;
    for(int i=0;i<len;++i) {
        if(s[i]!=p[0] && p[0]!='*')
            continue;
        for(int j=1;i+j<=len;++j) {
            if(check(p,s.substr(i,j))) {
                cout<<i<<" "<<j<<endl;
                flag=true;
            }
        }
    }
    if(!flag)
        cout<<"-1 0"<<endl;
    return 0;
}


发表于 2021-07-04 17:28:24 回复(0)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> // 宏定义:限制各模块的最大长度,防止内存溢出 #define MAX_PART_NUM 20 // 模式串被*拆分后的最大固定段数量 #define MAX_MATCH_NUM 10000 // 最大匹配结果存储数量,避免数组越界 #define MAX_PATTERN_LEN 21 // 模式串最大长度(含结束符) #define MAX_STRING_LEN 1001 // 目标串最大长度(含结束符) // 定义匹配结果的结构体:存储子串的起始位置和长度 typedef struct { int start; // 匹配子串在目标串中的起始下标(从0开始) int len; // 匹配子串的长度 } MatchResult; /** * @brief 排序函数:用于qsort的比较规则,按要求排序匹配结果 * @param a 待比较的第一个匹配结果指针 * @param b 待比较的第二个匹配结果指针 * @return 排序差值:起始位置升序,同位置按长度升序 */ int compareMatches(const void *a, const void *b) { // 强制类型转换为MatchResult指针,方便访问成员 MatchResult *ma = (MatchResult *)a; MatchResult *mb = (MatchResult *)b; // 优先按起始位置升序排列 if (ma->start != mb->start) { return ma->start - mb->start; } // 起始位置相同时,按子串长度升序排列 return ma->len - mb->len; } /** * @brief 去重函数:移除排序后结果中重复的匹配项 * @param matches 已排序的匹配结果数组 * @param count 原始匹配结果的数量 * @return 去重后的有效结果数量 */ int deduplicateMatches(MatchResult *matches, int count) { // 边界条件:无结果或只有1个结果时,无需去重 if (count <= 1) return count; int unique = 1; // 记录去重后的结果数量,初始为1(第一个结果默认唯一) // 从第二个结果开始遍历,与前一个唯一结果比较 for (int i = 1; i < count; i++) { // 起始位置或长度不同,视为不同结果 if (matches[i].start != matches[unique-1].start || matches[i].len != matches[unique-1].len) { matches[unique++] = matches[i]; // 存入唯一结果数组 } } return unique; // 返回去重后的数量 } /** * @brief 拆分模式串:将带*的模式串拆分为若干非*的固定段 * @param p 输入的模式串 * @param parts 输出的固定段数组,存储拆分后的每个子串 * @param partLens 输出的固定段长度数组,存储每个子串的长度 * @return 拆分后的固定段数量 */ int splitPattern(const char *p, char parts[][MAX_PATTERN_LEN], int *partLens) { int partNum = 0; // 记录拆分出的固定段数量 int currentLen = 0; // 记录当前正在拼接的固定段长度 int pLen = strlen(p); // 计算模式串的总长度 // 遍历模式串的每个字符 for (int i = 0; i < pLen; i++) { if (p[i] == '*') { // 遇到*分隔符 // 若当前已有拼接的字符(避免连续*导致空段) if (currentLen > 0) { parts[partNum][currentLen] = '\0'; // 给当前段加结束符 partLens[partNum] = currentLen; // 记录当前段长度 partNum++; // 段数加1 currentLen = 0; // 重置当前段长度,准备下一段 } } else { // 遇到普通字符,拼接到当前段 parts[partNum][currentLen++] = p[i]; } } // 处理模式串末尾的非*段(最后一个字符不是*的情况) if (currentLen > 0) { parts[partNum][currentLen] = '\0'; partLens[partNum] = currentLen; partNum++; } return partNum; // 返回最终拆分的段数 } /** * @brief 单段匹配检查:判断目标串从pos开始是否匹配指定固定段 * @param s 目标串 * @param sLen 目标串总长度 * @param pos 目标串的起始检查位置 * @param part 待匹配的固定段 * @param partLen 固定段的长度 * @return 匹配返回true,不匹配返回false */ bool matchSinglePart(const char *s, int sLen, int pos, const char *part, int partLen) { // 边界检查:起始位置+段长度超过目标串长度,直接不匹配 if (pos + partLen > sLen) return false; // 逐字符比较,判断是否完全匹配 for (int i = 0; i < partLen; i++) { if (s[pos + i] != part[i]) { return false; // 有一个字符不匹配则返回false } } return true; // 所有字符匹配,返回true } /** * @brief 核心匹配函数:查找目标串中所有符合模式串规则的子串 * @param p 模式串 * @param s 目标串 * @param matches 输出的匹配结果数组 * @return 匹配结果的总数量 */ int findAllMatches(const char *p, const char *s, MatchResult *matches) { int pLen = strlen(p); // 模式串长度 int sLen = strlen(s); // 目标串长度 char parts[MAX_PART_NUM][MAX_PATTERN_LEN]; // 存储拆分后的固定段 int partLens[MAX_PART_NUM]; // 存储每个固定段的长度 // 拆分模式串,得到固定段数量 int partNum = splitPattern(p, parts, partLens); int matchCount = 0; // 记录匹配结果的数量 // 情况1:模式串全是*(拆分后无固定段),匹配所有可能的子串 if (partNum == 0) { // 枚举所有起始位置(0到sLen,包含空串的情况) for (int start = 0; start <= sLen; start++) { // 枚举所有可能的长度(0到sLen-start,包含空串) for (int len = 0; start + len <= sLen; len++) { matches[matchCount].start = start; matches[matchCount].len = len; matchCount++; // 结果数量加1 } } return matchCount; // 直接返回所有可能的子串数量 } // 情况2:模式串含固定段,需要按顺序匹配所有固定段 int firstPartLen = partLens[0]; // 第一个固定段的长度 // 枚举第一个固定段在目标串中的所有可能起始位置 for (int i0 = 0; i0 <= sLen - firstPartLen; i0++) { // 检查目标串i0位置是否匹配第一个固定段 if (!matchSinglePart(s, sLen, i0, parts[0], firstPartLen)) { continue; // 不匹配则跳过当前i0,尝试下一个位置 } int currentPos = i0 + firstPartLen; // 记录第一个段匹配后的结束位置 bool isValid = true; // 标记是否所有段都匹配成功 // 依次匹配后续的每个固定段 for (int j = 1; j < partNum; j++) { int currPartLen = partLens[j]; // 当前待匹配段的长度 bool found = false; // 标记当前段是否找到匹配位置 // 从currentPos开始,枚举当前段的所有可能起始位置 for (int k = currentPos; k <= sLen - currPartLen; k++) { // 检查k位置是否匹配当前段 if (matchSinglePart(s, sLen, k, parts[j], currPartLen)) { currentPos = k + currPartLen; // 更新当前结束位置 found = true; // 标记找到匹配 break; // 找到后跳出循环,匹配下一段 } } // 当前段未找到匹配位置,整个模式匹配失败 if (!found) { isValid = false; break; } } // 所有固定段都匹配成功,记录结果 if (isValid) { matches[matchCount].start = i0; // 匹配子串的起始位置(第一个段的起始) matches[matchCount].len = currentPos - i0; // 匹配子串的总长度(结束位置-起始位置) matchCount++; // 结果数量加1 } } return matchCount; // 返回最终匹配结果数量 } int main() { char p[MAX_PATTERN_LEN], s[MAX_STRING_LEN]; // 定义模式串和目标串的存储数组 MatchResult matches[MAX_MATCH_NUM]; // 定义匹配结果数组 int matchCount; // 记录匹配结果数量 // 读取模式串:fgets读取含换行符,用strcspn去除换行符 fgets(p, MAX_PATTERN_LEN, stdin); p[strcspn(p, "\n")] = '\0'; // 读取目标串:同理去除换行符 fgets(s, MAX_STRING_LEN, stdin); s[strcspn(s, "\n")] = '\0'; // 调用核心函数,查找所有匹配结果 matchCount = findAllMatches(p, s, matches); // 对匹配结果排序+去重:保证结果有序且唯一 if (matchCount > 0) { // 使用qsort排序,比较规则为compareMatches函数 qsort(matches, matchCount, sizeof(MatchResult), compareMatches); // 去重处理 matchCount = deduplicateMatches(matches, matchCount); } // 输出结果:有匹配则逐行输出,无匹配则输出-1 0 if (matchCount > 0) { for (int i = 0; i < matchCount; i++) { printf("%d %d\n", matches[i].start, matches[i].len); } } else { printf("-1 0\n"); } return 0; } </stdbool.h></string.h></stdlib.h></stdio.h>
发表于 2026-01-10 19:09:00 回复(0)
from sre_constants import JUMP
p = input()
s = input()

star_index = 0
for i in range(0, len(p)):
    if p[i] == "*":
        star_index = i

start = p[:star_index]
stop = p[star_index + 1 :]
# print(start, stop)

A = []
for i in range(0, len(s)):
    for j in range(i, len(s)):
        temp = str()

        if start and stop:
            temp = start + s[i : j] + stop

        if not start and stop:
            temp = s[i : j] + stop

        if start and not stop:
            temp = start + s[i : j]

        if not start and not stop:
            temp = s[i : j]
        
        if temp in s:
            if temp not in A:
                A.append(temp)
# print(A)

if not A:
    print("-1 0")

R = []
if A:
    for i in range(0, len(A)):
        # print(A[i])
        if len(A[i]) >= 2:
            first = A[i][0]
            second = A[i][1]
        
            j = 0
            while True:
                if s[j] == first:
                    if s[j + 1]== second:
                        R.append([j, len(A[i])])
                        break
                j += 1

        if len(A[i]) == 1:
            first = A[i][0]

            j = 0
            while True:
                if s[j] == first:
                    R.append([j, 1])
                    break
                j += 1
  
R.sort()
# print(R)

if R:
    for i in R:
        t = str(i[0]) + " " + str(i[1])
        print(t)



通过率12/18,未通过用例如下,“对比”看不到,不知道哪里问题
*6
,X72EXH]MdDkqQoHR`'{}[zGJBudZZ,bV$.^7%<\vRpUug2pFS:uSsA9IR'M@s3n0#Y)yUXy:bta@2mASnwm(!\G5?lKMY!FE}|}ug\m`H85Ay;O)o@69+=/pGl,)KHykwX;V6<FynJmh1>7/@!,J[Ve\skQh-#c#xY2dYtHKEOR-cLBR+Z`7wRRbD$JgC_RY2mpL7`D^l%?bG#h\z(vryV:sFBA;`FwHi;;T?I5K_zV-O]Wbx'&WzX<+7y(HYk;Nd":h/!e_Q73HlK#0kLQ:ib;c?QUaDIT4qt';^SCT41)~p@i`=v4m\0[,IABz-lRgd9JP"^%N8r%-@}H'=A9mObtVHOvqf|H<)TmFfb9(b[3XQU>|\_TmmD[W(JK'yY3Blj:oVmR'?@CDiZt6`B|cg!&?v-;gT<wvKq;SJ@-AK!hK4FM=v=0g}{US9-AyVdHvU#;~~V(:`RNAV@MMhU$,gj~H3?X'w=U\a#noR1OKy#DdTG2d\jviZa7arTjJC<!a}$U;@Up'Kh_/}UJYgQN&}'`l{GJuWt|Ou>;.Cl%NN&/;h|.3(Wb/DnzMX8#yTEHy8k>KU_<DD/bQ/}WP#vN1%f{#73&GzchbXhB4lGt"zmi%hmW`!N"%wPL^&k4$?F+~B,/#s!S3Iswy2^%>S<k7IG,iyIrm$91uKyB(_'mgK,N2Qrp[&FrwIm)BrUn4T;bBOeT{0[1d~4#0~f^'CVA~7kqCN/9z;tuRHqsHqhfGa^Hxps/U},SxF1/T)bs;a7{E!jJx9f~9!l%Mu!sw>$.4dEdYd^fI_qtGA~J/v>+.P~a{Uxkep6fip,vJotw?BDX'\"?u#mPh^8>h

发表于 2026-01-04 21:25:17 回复(0)
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

var pStr, sStr string
var endPositions map[int]bool

// dfs: 从 sIdx 和 pIdx 开始尝试匹配
func dfs(sIdx, pIdx int) {
	if pIdx == len(pStr) {
		endPositions[sIdx] = true
		return
	}
	if sIdx == len(sStr) {
		return
	}

	if pStr[pIdx] == sStr[sIdx] {
		dfs(sIdx+1, pIdx+1)
	} else if pStr[pIdx] == '*' {
		// 三种情况:
		// 1. '*' 匹配空(跳过 '*')
		dfs(sIdx, pIdx+1)
		// 2. '*' 匹配当前字符,并继续用 '*' 匹配后续
		dfs(sIdx+1, pIdx)
		// 3. '*' 仅匹配当前字符
		dfs(sIdx+1, pIdx+1)
	}
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)

	scanner.Scan()
	pStr = scanner.Text()
	scanner.Scan()
	sStr = scanner.Text()

	foundMatch := false

	// 存储结果:起始位置 → 长度列表
	type Result struct {
		Start, Length int
	}
	var results []Result

	for i := 0; i < len(sStr); i++ {
		// 只有首字符匹配,或模式首字符是 '*' 才尝试匹配
		if pStr[0] == '*' ||
			pStr[0] == sStr[i] {

			endPositions = make(map[int]bool) // 清空上次结果
			dfs(i, 0)

			if len(endPositions) > 0 {
				foundMatch = true
				// 收集所有有效的匹配(长度 > 0)
				for endPos := range endPositions {
					if endPos > i {
						results = append(results, Result{Start: i, Length: endPos - i})
					}
				}
			}
		}
	}

	// 去重并排序:按起始位置,再按长度
	uniqueResults := make(map[string]bool)
	var finalResults []Result
	for _, r := range results {
		key := strconv.Itoa(r.Start) + "," + strconv.Itoa(r.Length)
		if !uniqueResults[key] {
			uniqueResults[key] = true
			finalResults = append(finalResults, r)
		}
	}

	// 排序输出
	sort.Slice(finalResults, func(i, j int) bool {
		if finalResults[i].Start == finalResults[j].Start {
			return finalResults[i].Length < finalResults[j].Length
		}
		return finalResults[i].Start < finalResults[j].Start
	})

	// 输出结果
	if foundMatch && len(finalResults) > 0 {
		for _, r := range finalResults {
			fmt.Printf("%d %d\n", r.Start, r.Length)
		}
	} else {
		fmt.Println("-1 0")
	}
}

发表于 2025-09-07 22:51:05 回复(0)
参考了其他同仁的递归思路,之前用非递归的解法也能AC全部case,但是代码繁琐,还是递归的写法更简洁。

#include <string>
#include <iostream>
#include <set>    //需要使用有序的集合
using namespace std;

set<int> matchedPos;

void ExgrexMatch(string& pattern, int pos1, string& str, int pos2) {
    if(pos1 == pattern.length()) {    //str[j:pos2) 是匹配的
        matchedPos.insert(pos2);
    }
    if(pos2 == str.length()) {    //str结束
        return;
    }
    
    if(pattern[pos1] == str[pos2]) {    //匹配1个
        ExgrexMatch(pattern, pos1+1, str, pos2+1);
    }
    else if(pattern[pos1] == '*') {
        ExgrexMatch(pattern, pos1+1, str, pos2);    //*匹配0个字符
        ExgrexMatch(pattern, pos1+1, str, pos2+1);  //*匹配1个字符
        ExgrexMatch(pattern, pos1, str, pos2+1);    //*匹配多个字符
    }
    else {    // pattern[pos1] != '*' && pattern[pos1] != str[pos2]
        return;    //此路不匹配
    }
}

int main() {
    string pattern, str;
    cin >> pattern >> str;
    
    int len1 = pattern.length();
    int len2 = str.length();
    bool someMatched = false;
    for(int j = 0; j < len2; j++) {
        if(str[j] == pattern[0] || pattern[0] == '*') {
            ExgrexMatch(pattern, 0, str, j);
            if(!matchedPos.empty()) {
                someMatched = true;
                for(auto pos : matchedPos) {
                    if(pos > j) {    //*匹配0个字符的时候,pos-j为0,
                                     //此时不应输出
                        cout << j << " " << pos - j << endl;
                    }
                }
                matchedPos.clear();    //清除开始下一轮
            }
        }
    }
    if(!someMatched) {
        cout << -1 << " " << 0 << endl;
    }
    return 0;
}


发表于 2021-03-28 21:58:07 回复(5)
主要是分成了两部分,一个是匹配方法和另一个是输入匹配的两个字段找寻方法:

首先用两个双循环做两个匹配字段搜寻,匹配字段为输入的需要匹配的字段1与带星号的匹配字段2两个,当(字段1 的首位字母与字段2相同)||或者(字段2的首字母是“*”,字段1的末端字母与字段2末端其匹配)||或者(字段2的末端字母是“*”号,字段1的首段字母与字段2首段匹配)||或者(字段2长度只有1,且是“*”号)

当上述条件满足时进行这两个两个字段的匹配,匹配方法返回true和false。

匹配的代码可以参考leetcode原题,或者剑指offer 第52题“正则表达式匹配”。

每次匹配得到true,就把正确的答案输出。。直接输出不会超时。。
我一开始还是因为刷题的惯性思维想把他们放在一个set里面最后输出结果超时了。。

import java.util.*;
public class Main{
     
    public static boolean check(String str2,String str1){
        boolean[][] dp=new boolean[str2.length()+1][str1.length()+1];
        int rows=dp.length;
        int cols=dp[0].length;
        dp[0][0]=true;
        for(int i=1;i<cols;i++){
            if(str1.charAt(i-1)=='*'){
                dp[0][i]=dp[0][i-1];
            }
        }
         //这个几乎就是leetcode原题了,但是leetcode题太多了所以没找到
        // 剑指offer第52题的思路也是一样的
        for(int i=1;i<rows;i++){
            for(int j=1;j<cols;j++){
                if(str2.charAt(i-1)==str1.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else if(str1.charAt(j-1)=='*'){
                    dp[i][j]=dp[i-1][j]||dp[i][j-1];
                }
            }
        }
        return dp[rows-1][cols-1];
    }
     
    public static void main(String[]args){
        Scanner sc=new Scanner(System.in);
        String str1="";
        String str2="";
        while(sc.hasNext()){
            str1=sc.next();
            str2=sc.next();
        }
        //TreeSet<int[]> res=new TreeSet<>((a,b)->(a[0]==b[0]?a[1]-b[1]:a[0]-b[0]));
        int len2=str2.length();
        int len1=str1.length();
        int count=0;
        if(len1>=1){
        for(int i=0;i<len2;i++){
            for(int j=i;j<len2;j++){
                if(str2.charAt(i)==str1.charAt(0)&&str2.charAt(j)==str1.charAt(len1-1)){
                    if(check(str2.substring(i,j+1),str1)){
                        StringBuilder s=new StringBuilder();
                        s.append(i);
                        s.append(" ");
                        s.append(j-i+1);
                        System.out.println(s.toString());
                        count++;
                    }
                }else if(str1.charAt(0)=='*'&&(str2.charAt(j)==str1.charAt(len1-1)||len1==1)){
                    if(check(str2.substring(i,j+1),str1)){
                       StringBuilder s=new StringBuilder();
                        s.append(i);
                        s.append(" ");
                        s.append(j-i+1);
                        System.out.println(s.toString());
                        count++;
                    }
                }else if(str1.charAt(len1-1)=='*'&&(str2.charAt(i)==str1.charAt(0)||len1==1)){
                    if(check(str2.substring(i,j+1),str1)){
                        StringBuilder s=new StringBuilder();
                        s.append(i);
                        s.append(" ");
                        s.append(j-i+1);
                        System.out.println(s.toString());
                        count++;
                    }
                }
            }
        }
    }
          if(count==0) {
            System.out.print("-1 0");
        }
 
        /*if(res.size()<=0){
            System.out.print("-1 0");
        }else{
                   for(int[] temp:res){
            for(int j=0;j<temp.length;j++){
              if(j==temp.length-1){
                    System.out.print(temp[j]);
                  break;
                }
                System.out.print(temp[j]+" ");
            }
            System.out.print("\n");
        }
        }
        */
 
    }
}



编辑于 2020-12-10 11:24:57 回复(0)
Scanner scanner=new Scanner(System.in); String str1=scanner.nextLine(); String str2=scanner.nextLine(); String[] list = str1.split("\\*"); String s1=list[0]; String s2=list[1]; int begin=str2.indexOf(s1); while(begin!=-1){ int end=str2.indexOf(s2,begin);  while(end!=-1){
        System.out.println(begin+" "+(end+s2.length()-begin));  end=str2.indexOf(s2,end+1);  }
    begin=str2.indexOf(s1,begin+1); }
发表于 2020-07-29 20:39:19 回复(0)
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * 实现字通配符*
 *
 * @author WU Jiahui
 * @date 2020/07/28 11:24
 */


public class Main {
    static boolean found = false;

    public static void search(char[] target, char[] text, int begin, int targetCur, int textCur, Set<Integer> set) {
        if (targetCur == target.length
                || (textCur == text.length && targetCur == (target.length - 1) && target[targetCur] == '*')) {
            found = true;
            if (!set.contains(textCur - begin) && textCur != begin) {
                set.add(textCur - begin);
                System.out.printf("%d %d\n", begin, textCur - begin);
            }
            return;
        }

        if (textCur == text.length) {
            return;
        }

        if (target[targetCur] == '*') {
            search(target, text, begin, targetCur + 1, textCur, set);
            search(target, text, begin, targetCur + 1, textCur + 1, set);
            search(target, text, begin, targetCur, textCur + 1, set);
        } else if (target[targetCur] == text[textCur]) {
            search(target, text, begin, targetCur + 1, textCur + 1, set);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String targetStr = scanner.nextLine();
        String textStr = scanner.nextLine();
        char[] target = targetStr.toCharArray();
        char[] text = textStr.toCharArray();
        for (int i = 0; i < text.length; i++) {
            search(target, text, i, 0, i, new HashSet<>());
        }
        if (!found) {
            System.out.printf("%d %d\n", -1, 0);
        }
    }
}

发表于 2020-07-28 16:57:27 回复(0)
import sys

class Solution:
    def match(i, j):
        # Terminator:当t每个元素都匹配到
        if j == len(t):
            ans.add(i)
            # 千万不能忘记return
            return
        # 当前索引相等(小心越界)
        if i < len(s) and s[i] == t[j]:
            Solution.match(i + 1, j + 1)
        elif i < len(s) and t[j] == '*':
            # 1. 让*代表nothing
            Solution.match(i, j + 1)
            # 2. 让x代表s[i]
            Solution.match(i + 1, j + 1)
            # 2. 让*代表多个字符
            Solution.match(i + 1, j)
        return

if __name__ == "__main__":
    while True:
        # 读取第一行
        t = sys.stdin.readline().strip()
        if t == '':
            break
        s = input()
        # 存储答案
        ans = set()
        # 初始化没找到
        if_find = False
        # 定字符的开始坐标i
        for i in range(len(s)):
            if s[i] == t[0]&nbs***bsp;t[0] == '*':
                Solution.match(i, 0)
            if len(ans):
                if_find = True
                for last_index in sorted(ans):
                    if last_index > i:
                        print(i, last_index - i)
            ans.clear()
        if not if_find:
            print(-1, 0)

发表于 2020-07-21 17:07:22 回复(0)
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		char[] pat = sc.next().toCharArray();
		char[] str = sc.next().toCharArray();
        int count=0;

		for (int i = 0; i < str.length; i++) {
			for (int j = i; j < str.length; j++) {
				// 匹配str[i..j]
				if (match(pat, str, 0, i, j)) {
					System.out.println( String.valueOf(i) + " " + String.valueOf(j - i + 1));
                    count++;
				}
			}
		}
        if(count==0){
            System.out.println("-1 0");
        }
	}

	public static boolean match(char[] pat, char[] str, int pIndex, int left, int right) {

		if (pIndex == pat.length && left > right) {
            //恰好匹配完
			return true;
        }
		if (left > right && pIndex != pat.length && pat[pIndex] != '*') {
			//pat过长
            return false;
		}
        if (pIndex == pat.length && right >= left) {
			// str过长
			return false;
		}
		// pIndex!=length
		else if (pat[pIndex] == '*') {
			if (left > right) {
				return match(pat, str, pIndex + 1, left, right);
			} else {
				return match(pat, str, pIndex, left + 1, right) || match(pat, str, pIndex + 1, left, right);
			}
		} else if (left <= right && pat[pIndex] == str[left]) {
			return match(pat, str, pIndex + 1, left + 1, right);
		} else if (left <= right && pat[pIndex] != str[left]) {
			return false;
		} else {
			return false;
		}
	}
}
应该是暴力过,递归处理*那挺巧妙的

发表于 2020-07-14 17:30:52 回复(0)
参考上面nbgao写的java代码。搞不懂,他的能通过,但是我我改成思路完全一致的Java代码就不通过。
修改了几个bug才通过的。

import java.util.*;
public class Main{
    private static ArrayList<Integer> list = new ArrayList<>();
    private static char [] t;
    private static char [] s;
    public static void main(String[]args){
        Scanner sc = new Scanner(System.in);
        String str1 = sc.nextLine();
        String str2 = sc.nextLine();
        t = str1.toCharArray();
        s = str2.toCharArray();
        int flag = -1;
        for(int i = 0; i< s.length; i++){
            if(s[i] == t[0] || t[0] == '*'){
                DFS(i,0);
                if(!list.isEmpty())flag = 1;
                for(Integer num:list){
                    //特殊情况:当t串的最后一个字符是*时
                    //例如t="*";s="shop"一种输出是(0,1)
                    //当i=0;j=0;时 运行到代码if(t[j]=='*')DFS(i,j+1) 
                    //比较s的当前字符与t中*的下一个字符,由于*就是最后一个字符
                    //j值为t.length时,i的值为0,得到的输出结果为(0,0)
                    if(t[t.length-1]=='*'){
                        System.out.println(i+" "+(num-i+1));
                    }else{
                        System.out.println(i+" "+(num-i));
                    }
                }
                list.clear();
            }
        }
        if(flag == -1){
            System.out.println(flag+" "+0);
        }
    }
//i遍历字符串s,j遍历模式串t
    private static void DFS(int i, int j){
        if(j == t.length){
            list.add(i);
            return;
        }            
        if(i == s.length)
            return;
        if(s[i] == t[j]){
            DFS(i+1,j+1);
        }else if(t[j] == '*'){
            //*代表0个字符,比较s的当前字符与t中*的下一个字符
            DFS(i,j+1);
            //*代表多个字符,比较s的下一个字符与t中*
            DFS(i+1,j);
            //DFS(i+1,j+1);
        }
        return;
    }
}


发表于 2020-07-14 13:26:01 回复(0)
#include <iostream>
#include <algorithm>
#include <set>

using namespace std;

string s, t;
set<int> q;

void dfs(int i, int j)
{
    if(j == s.size())  q.insert(i);
    if(i == t.size())  return;
    
    if(t[i] == s[j])  dfs(i+1, j+1);
    else if(s[j] == '*')
    {
        dfs(i, j+1);
        dfs(i+1, j);
        dfs(i+1, j+1);
    }
}

int main()
{
    cin >> s >> t;
    bool flag = false;
    for(int i = 0; i < t.size(); i++)
    {
        if(s[0] == '*' || s[0] == t[i])
            dfs(i, 0);
        if(q.size())
        {
            flag = true;
            for(auto x : q)
                if(x > i)  cout << i << ' ' << x-i << endl;
        }
        q.clear();
    }
    if(!flag)   cout << -1 << ' ' << 0 << endl;
    
    return 0;
}

发表于 2020-07-10 17:12:06 回复(0)
动态规划+适当剪枝即可AC,新人欢迎指导
def shipei(a,b):
    j=-1
    if a=='*':
        return True
    if '*' not in a:
        if len(a)!=len(b):
            return False
    for i in range(len(a)):
        j+=1
        if a[i]=='*':
            sp=False
            s=a[i+1::]
            for k in range(j,len(b)):
                sp=sp&nbs***bsp;shipei(s,b[k::])
            return sp
        else:
            if j<len(b):
                if a[i]!=b[j]&nbs***bsp;j>len(b):
                    return False
            else:
                return False
    return True
while True:
    try:
        str1=input()
        str2=input()
        n=0
        ans=[]
        sy=1
        x=str1[0]
        for i in range(len(str2)):
            if x==str2[i]&nbs***bsp;x=='*':
                for j in range(len(str2)):
                    if shipei(str1,str2[i:j+1]) and (j-i+1)>0:
                        sy=0
                        print(str(i)+' '+str(j-i+1))
        if sy==1:
            print('-1 0')
    except:
        break

发表于 2020-06-30 15:45:31 回复(2)
动态规划过不去,内存不足。建议直接上回溯。
发表于 2020-06-24 09:59:27 回复(0)
import java.util.*;
public class Main{
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String pattern = sc.next();
        String str = sc.next();
        String[] pats = pattern.split("\\*");
        if(pattern.endsWith("*")){
            pats = Arrays.copyOf(pats,pats.length+1);
            pats[pats.length-1] = "";
        }
        if(pats.length >= 2){
            List<String> matches = new ArrayList<String>();
            int fromIndex = 0;
            while(true){
                boolean isEmpty = pats[0].equals("");
                int step = pats[0].equals("")?1:pats[0].length();
                int position = str.indexOf(pats[0],fromIndex);
                if(position > -1 && position < str.length()){
                    fromIndex = position + step;
                    matches = findNext(position, position + (isEmpty?0:step),1,pats, str, matches);
                }else{
                    break;
                }
            }
            if(matches.size() > 0){
                for(String s:matches){
                    System.out.println(s);
                }
            }else{
                System.out.println("-1 0");
            }

        }else if(pattern.equals("*")){
            for(int i =0 ; i<str.length(); i++){
                for(int j = i; j<str.length(); j++){
                    System.out.println(i+" "+(j-i+1));
                }
            }
        }else{
            System.out.println("-1 0");
        }

    }

    private static List<String> findNext( int startIndex, int fromIndex, int signIndex, String[] pats, String str, List<String> matches){
        fromIndex -= pats[signIndex].equals("")?1:0;
        while(true){
            int step = pats[signIndex].equals("")?1:pats[signIndex].length();
            int position = str.indexOf(pats[signIndex], fromIndex);
            if(position > -1 && position < str.length()){
                fromIndex = position + step;
            }else{
                break;
            }
            if(signIndex < pats.length -1){
                findNext(startIndex,fromIndex, signIndex+1,pats,str,matches);
            }else{
                matches.add(startIndex+" "+(position+step-startIndex));
            }
        }

        return matches;
    }
}
发表于 2020-06-22 10:39:24 回复(0)
隆盛科技斐林试剂复试了的答案加了点自己理解后的注释,下次见到了这题可以自己看看
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
  
public class Main {
    private static boolean match(String matchStr, String str, int matchIdx, int idx) {
        if (matchIdx == matchStr.length() && idx == str.length()) {
            return true;
        }
        //str匹配到最后一个字符了,matchIdx后面还有多个*的情况
        if (idx == str.length() && matchIdx < matchStr.length() && matchStr.charAt(matchIdx) == '*') {
           return match(matchStr, str, matchIdx + 1, idx);
        }
        if (matchIdx >= matchStr.length() || idx >= str.length()) {
            return false;
        }
        //匹配中出现了不同的字符
        if (matchStr.charAt(matchIdx) != '*' && matchStr.charAt(matchIdx) != str.charAt(idx)) {
            return false;
        }
        boolean flag = false;
        //匹配中对*处理,*能表示多个字符,所以idx + 1,直到到达str的最后一个字符
        if (matchStr.charAt(matchIdx) == '*') {
            flag = match(matchStr, str, matchIdx + 1, idx) || match(matchStr, str, matchIdx, idx + 1);
        }
        //匹配中两个字符串的字符相同的情况,用与或保证可以从false变回true
        if (matchStr.charAt(matchIdx) == str.charAt(idx)) {
            flag |= match(matchStr, str, matchIdx + 1, idx + 1);
        }
        return flag;
    }
  
    private static List<Integer[]> getMatchPosAndLen(String matchStr, String str) {
        List<Integer[]> ans = new ArrayList<>();
         //找到头尾都相等的情况
        for (int i = 0; i < str.length(); ++i) {
            //保证第一个字符相同
            if (matchStr.charAt(0) != '*' && matchStr.charAt(0) != str.charAt(i)) {
                continue;
            }
           
            for (int j = i; j < str.length(); ++j) {
                //保证最后一个字符相同
                if (matchStr.charAt(matchStr.length() - 1) != '*' && matchStr.charAt(matchStr.length() - 1) != str.charAt(j)) {
                    continue;
                }
                if (match(matchStr, str.substring(i, j + 1), 0, 0)) {
                    ans.add(new Integer[]{i, j - i + 1});
                }
            }
        }
        if (ans.size() == 0) {
            ans.add(new Integer[]{-1, 0});
        }
        return ans;
    }
  
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
         String matchStr = in.next();
        String str = in.next();
        List<Integer[]> list = getMatchPosAndLen(matchStr, str);
        for (Integer[] arr : list) {
            System.out.println(arr[0] + " " + arr[1]);
        }
  
    }
}


发表于 2020-06-14 12:14:42 回复(0)

热门推荐

通过挑战的用户

查看代码
实现字通配符*