首页 > 试题广场 >

序列模式匹配

[编程题]序列模式匹配
  • 热度指数:3077 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
给定文本text和待匹配字符串pattern,二者皆只包含小写字母,并且不为空。
在text中找出匹配pattern的最短字符串,匹配指按序包含pattern,但不要求pattern连续。
如text为abaacxbcbbbbacc,pattern为cbc,text中满足条件的是abaacxbcbbbbacc下划线部分。

输入描述:
多行,每行一个text和一个pattern,用空格分隔。
保证1<=|text|,|pattern|<=1000,Σ|text|,Σ|pattern|<=10000。


输出描述:
输出最短匹配序列起止位置(位置下标从0开始),用空格分隔。若有多个答案,输出起止位置最小的答案;若无满足条件的答案,则起止均为-1。
示例1

输入

abaacxbcbbbbacc cbc
abc x
aaabcac ac

输出

4 7
-1 -1
5 6
/*
暴力枚举应该也能通过,以下介绍一种动态规划算法
设dp[i][i+k]为text从i到i+k匹配到的pattern最长的长度
当text[i+k]==pattern[dp[i][i + k - 1]]时, dp[i][i + k] = dp[i][i + k - 1] + 1;
否则  dp[i][i + k] = dp[i][i + k - 1] 。
边界为 k=0时,dp[i][i] = (text[i] == pattern[0]);

因为要求最短匹配序列,所以k从0到n遍历;
又因为多个答案时输出起止位置最小的答案,所以i从0开始遍历。
此时第一个结果即为符合要求的答案
*/
#include<bits/stdc++.h>
using namespace std;
#define N 1000

int main()
{
//    freopen("input.txt", "r", stdin);
    char text[N], pattern[N];
    while(cin >> text >> pattern) {
        int n = strlen(text), m = strlen(pattern);
        int dp[n][n];
        memset(dp, 0, sizeof(dp));
        bool flag = false;
        for(int k = 0; k < n; k++) {
            for(int i = 0; i + k < n; i++) {
                dp[i][i + k] = dp[i][max(i + k - 1, 0)] + (text[i + k] == pattern[dp[i][max(i + k - 1, 0)]]);
                if(dp[i][i + k] >= m) {
                    flag = true;
                    cout << i << " " << i + k << endl;
                }
                if(flag) break;
            }
            if(flag) break;
        }
        if(!flag) cout << "-1 -1" << endl;
    }
    return 0;
}

发表于 2019-07-13 16:58:12 回复(1)
这个题有问题吧,给的范例和运行的用例,两个结果不一样
发表于 2019-12-25 18:44:42 回复(0)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string a,b;
    while(cin>>a>>b)
    {
        int s=-1,e=-1,minn=1001;
         for(int i=0;i<=a.length()-b.length();i++)
         {
             if(a.find(b[b.length()-1],i+1)==a.npos||a.find(b[0],i)==a.npos)   break;
             int temp=a.find(b[0],i),flag=0;
             for(int j=1;j<b.length();j++)
             {
                 if(a.find(b[j],temp+1)!=a.npos)    
                     temp=a.find(b[j],temp+1);                 
                 else    {flag=1;break;}
             }
             int cnm=minn;
             if(!flag)    minn=min(minn,temp-(int)a.find(b[0],i));
             else break;
             if(minn!=cnm)    {e=temp;s=a.find(b[0],i);}
         }
        cout<<s<<" "<<e<<endl;  
    }
}
暴力,多加几个限制条件,速度也很快,逻辑更简单。
发表于 2022-04-04 23:27:25 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    string s,t;
    while(cin>>s>>t){
        int n=s.length(), m=t.length(), a=-1, b=-1, l, r, Min=INT_MAX;
        for(int i=0,j=0;i<n;i++){
            if(s[i]==t[j]){
                if(j==0)
                    a = i;
                j++;
            }
            if(j==m){
                j = 0;
                b = i;
                if(b-a<Min){
                    Min = b - a;
                    l = a;
                    r = b;
                }
                i = a;
            }
        }
        if(b==-1)
            cout<<-1<<" "<<-1<<endl;
        else
            cout<<l<<" "<<r<<endl;
    }
    return 0;
}

发表于 2019-12-07 00:42:18 回复(0)
测试用例有一个卡住了………………
题目要求的第一个字符串中含有的pattern串不用连续,所以很简单的就是遍历第一个字符串,以
一个下标来j取第二个字符串pattern串中的元素,如果相等,则j++即可,最后循环外判断一下j的
值。
#include<iostream>
#include<string>
#include<vector>
using namespace std;

int main()
{
    string s1,s2;
    while(cin>>s1>>s2)
    {
        int j=0;
        vector<int> begin;
        for(int i=0;i<s1.size();i++)
        {
            if(j==s2.size())
                break;
            if(s1[i]==s2[j])
            {
                begin.push_back(i);
                j++;
            }
        }
        if(j==s2.size())
        {
            cout<<begin[0]<<' '<<begin[begin.size()-1]<<endl;
        }
        else{
            cout<<-1<<' '<<-1<<endl;
        }
    }
}

发表于 2019-10-28 20:06:02 回复(0)
给的数据是不是有问题?第三个为什么是5,6,不是说有多个选择序列最小的吗
发表于 2019-08-27 21:59:26 回复(1)
到底是起止地址最小,还是长度最小?
发表于 2019-12-18 19:49:31 回复(0)
def match(s1, s2):
    if len(s1)<len(s2):return(-1,-1)
    i,j=0,0
    l,r,min_l = -1,-1,len(s1)+1
    while i<len(s1):
        if s1[i]==s2[j]:
            if j==len(s2)-1:
                k = i
                while(j>=0):
                    if s1[i]==s2[j]:
                        j-=1
                    i-=1
                i+=1
                temp_min = k-i+1
                if temp_min<min_l:
                    l,r,min_l = i,k,temp_min
            else:
                i+=1
                j+=1
        else:
            i+=1
    return (l,r)
while True:
    try:
        s1,s2 = input().split(' ')
        l,r = match(s1,s2)
        print(l,r)
    except:
        break

发表于 2019-07-11 21:00:47 回复(1)
#include <iostream>
#include <string>
#include <climits>
using namespace std;
int main(){
    string s,t;
    while(cin>>s>>t){
        int n=s.size(),m=t.size(),a=-1,b=-1,l=-1,r=-1,min=INT_MAX;
        for (int i=0,j=0;i<n;i++){
            if (s[i]==t[j]){
                if (j==0)
                    a=i;
                j++;
            }
            if (j==m){
                b=i,j=0;
                if (b-a<min){
                    min=b-a;
                    l=a,r=b;
                }
                i=a;
            }
        }
        cout<<l<<" "<<r<<endl;
    }
}
编辑于 2020-04-22 18:10:58 回复(0)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

/**
 * 给定文本text和待匹配字符串pattern,二者皆只包含小写字母,并且不为空。
 * 在text中找出匹配pattern的最短字符串,匹配指按序包含pattern,但不要求pattern连续。
 * 如text为abaacxbcbbbbacc,pattern为cbc,text中满足条件的是abaacxbcbbbbacc下划线部分。
 *
 * @author lihaoyu
 * @date 2019/11/5 20:12
 */
public class Main {

    private static class Point implements Comparable<Point>{
        int start;
        int end;

        public Point(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        public int compareTo(Point o) {
            if((end - start) != (o.end - o.start)){
              return  (end - start) - (o.end - o.start);
            }
            return start - o.start;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            String text = scanner.next();
            String pattern = scanner.next();
            int i = 0, j = 0, k = 0;
            int start = -1, end = -1;
            List<Point> res = new ArrayList<>();
            while(k < text.length()){
                start = -1;
                end = -1;
                i = k;
                j = 0;
                while(i < text.length() && j < pattern.length()){
                    if(text.charAt(i) == pattern.charAt(j)){
                        if(j == 0){
                            start = i;
                        }
                        if(j == pattern.length() - 1){
                            end = i;
                            break;
                        }
                        i++;
                        j++;
                    }else{
                        i++;
                    }
                }
                if(end != -1){
                    res.add(new Point(start,end));
//                    System.out.println(start + "   "+ end);
                }
                k++;
                while(k < text.length() && text.charAt(k) != pattern.charAt(0)){
                    k++;
                }
            }
            if(res.isEmpty()){
                System.out.println("-1 -1");
                continue;
            }
            Collections.sort(res);
            System.out.println(res.get(0).start+" " +res.get(0).end);
        }

    }
}


编辑于 2019-12-13 19:14:06 回复(3)
import sys

def func(a, b):
    temp = {}
    i = 0
    j = 0
    start = -1
    end = -1
    
    while i < len(a):
        if a[i] == b[j]:
            j += 1
            
            if start == -1:
                start = i
                end = i
            else:
                end = i
            
            if j == len(b):
                if end - start not in temp:
                    temp[end-start] = [start, end]
                i = start
                j = 0
                start = -1
        i += 1
    if len(temp) > 0:
        res = temp[min(temp.keys())]
    else:
        res = [-1, -1]
    res_str = str(res[0]) + " " + str(res[1])
    print(res_str)


lines = sys.stdin.readlines()
for line in lines:
    text, pattern = line.strip().split()
    func(text, pattern)


                                                                                    
发表于 2019-09-08 10:49:30 回复(1)

动态规划是O(n^2)复杂度,暴力也是O(n^2)复杂度,干脆暴力了事。

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            String s = sc.next();
            String t = sc.next();

            int min = s.length() + 1;
            int start = -1;
            int end = -1;
            for(int i = 0; i < s.length(); i ++) {
                if(s.charAt(i) == t.charAt(0)) {
                    int k = 0;
                    int j = i;
                    while(j < s.length() && k < t.length()) {
                        if(s.charAt(j) == t.charAt(k)) {
                            k ++;
                        }

                        j ++;
                        if(j - i >= min) break;
                    }

                    if(k == t.length() && (j - i) < min) {
                        min = j - i;
                        start = i;
                        end = j - 1;
                    }
                }
            }

            System.out.println(start + " " + end);
        }
    }
}
发表于 2019-08-20 00:07:02 回复(2)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string text,pattern;
    while(cin>>text>>pattern)
    {
        int len1=text.size();
        int len2=pattern.size();
        int i=0,j,k,start;
        const int INF=0x3f3f3f3f;
        int minLen=INF;
        while(i<len1)//遍历text,只要遇到pattern[0]就开始匹配判断
        {
            if(text[i]==pattern[0]){
               j=0;
               for(k=i;k<len1;++k){//检测[i,len1)之间的字符是否能够完全匹配pattern
                   if(text[k]==pattern[j])//检查能够匹配到的pattern字符
                       j++;
                   if(j==len2){//找到了一个匹配,此时i指向text中第一个匹配pattern[0]的位置
                       if(minLen>k-i+1){
                          minLen=k-i+1;
                          start=i;
                       }
                       break;
                   }    
               }
            }
            ++i;
        }
        if(minLen==INF){
            cout<<"-1 -1"<<endl;
        }else{
            cout<<start<<" "<<start+minLen-1<<endl;
        }
    }
}

发表于 2019-08-14 19:52:54 回复(0)
通过率15%--哎
#include<bits/stdc++.h>
usingnamespacestd;
 
vector <int> ftom (string s,string fs,intn)//默认n=0;n为了搜寻最小起止点
{
    intlen1=s.size();
    intlen2=fs.size();
    intpw=n;
    inttemp,flag=0;             //temp为搜寻目标,pw为起始搜寻点,flag为匹配个数
    vector<int> p(2,-1);
       
    for(inti=0;i<len2;++i)
    {
        temp=fs[flag];     //从0开始
        for(intj=pw;j<len1;++j)
        {
            if(temp==s[j])
            {
                ++flag;
                if(flag==1) p[0]=j;
                elseif(flag==len2) p[1]=j;
                else;
                pw=j+1;
                break;
            }
        }
    }
    if(p[0]==-1||p[1]==-1) p[0]=p[1]=-1;
    returnp;  
}
intmain()
{
string s1;
while(cin>>s1)
{
    string s2;
    cin>>s2;
    intlen=s1.size();
    charte[len];
    intnum=0;
    intbp=-1,ep=-1;
     
    vector<vector <int> > v(len,vector <int>(2,0));   //二维可变数组
    for(inti=0;i<len;++i)
    {
        v[i]=ftom (s1,s2,i);
        num=v[i][1]-v[i][0];
        if(num!=0)
            {te[i]=num;
            //cout<<v[i][0]<<' '<<v[i][1]<<endl;
            } //存储目标起始位置te[i]-->我牛逼了
    }
     
    intmin=1001,min_w,c;           //找min设最大值找最小的te[i],标记i值;
    for(inti=len-1;i>0;--i)          //同差值,选起始位置小的-->逆序处理即可
    {
        if(min>te[i]&&te[i]>0)
        {
            min_w=i;min=te[i];
        }  
    }
     
    if(min==0)
        bp=ep=-1;
    else
    {
        bp=v[min_w][0]; ep=v[min_w][1];
    }  
    cout<<bp<<' '<<ep<<endl;
}
    return0;
}

编辑于 2019-05-09 22:37:33 回复(0)
#include <iostream>
#include <string>
#include <tuple>
 
using namespace std;
 
tuple<int,int> getResult(const string& in,const string& s) {
    if(s.size() == 1) {
        auto f = in.find(s);
        if(f != string::npos)
            return make_tuple(f,f);
        else
            return make_tuple(-1,-1);
    }
    auto len = in.size();
    auto last = len - 1;
    auto min = 99999;
    auto left = -1,right = -1;
    for(int i = last; i >= 0; --i) {
        if(s[0] == in[i]) {
            auto p = 1;
            auto pos = -1;
            for(int j = i + 1;j <= len - 1; ++j) {
                if(s[p] == in[j]) {
                    ++p;
                    if(p == s.size()) {
                        pos = j;
                        break;
                    }
                }
            }
            
            if(pos != -1) {
                if(pos - i <= min) {
                    min = pos - i;
                    left = i;
                    right = pos;
                }
            }
            last = i;
        }
    }
    return make_tuple(left,right);
}
 
 
int main() {
    string input;
    while(cin>>input) {
        string toFind;
        cin>>toFind;
        auto res = getResult(input,toFind);
        cout<<std::get<0>(res)<<' ';
        cout << std::get<1>(res)<<'\n';
    }
    return 0;
}


发表于 2019-04-08 22:30:18 回复(0)
放一个自己的思路,先strstr查找符合目标字符串的;没有完整存在的目标串则使用strchr在查找每一个字符,找到最后一位,记录终止位置;反向字符串再找回第一个字符的位置,有重复的字符挪动一位;有不足的地方是有的用例没过,不太明白啥意思

#include <stdio.h>
#include <string.h>
#include <time.h>

int revers(char *pstr);

int Findstr(char *text, char *pattern, int *start, int *end)
{
    char *tmp,*tmp2,*p1;
    char newtmp[1024]={0};
    int i,j,length,b=0;
    
    if(pattern == NULL || text == NULL)
    {
        *start = -1;
        *end = -1;
    }

    p1 = text;
    length = strlen(pattern);
    
    if(tmp = strstr(text,pattern))
    {
        *start = tmp-text;
        *end = *start + length - 1;
    }
    else
    { 
        //end字符的位置,有重复的字符,tmp++
        for(i=0;i<length;i++)
        {
            tmp = strchr(p1,pattern[i]);
            //printf("%d:%c %s\n",__LINE__,pattern[i],tmp);
            if(NULL != tmp)
            {
                p1 = tmp;
                //特殊情况,连续的相同字符串,将新字符串起始位+1后再搜索
                if(i<(length-1) && pattern[i] == pattern[i+1])
                {
                    p1++;
                }
                *end = tmp - text;
            }
            else
            {
                *end = -1;
                *start = -1;
                return -1;
            }
        }

        ////printf("%d\n",*end);
        
        //start字符的位置,从end的位置反向找起点
        strncpy(newtmp,text,*end+1);
        revers(newtmp);    
        tmp2 = newtmp;
        //printf("%d,%s %d\n",__LINE__,tmp2,*end);

        for(i = length;i>0;i--)
        {   
            if(tmp = strchr(tmp2,pattern[i-1]))
            {
                tmp2 = tmp;
                //特殊情况,连续的相同字符串,将新字符串起始位+1后再搜索
                if(pattern[i] == pattern[i-1])
                {
                    tmp2++;
                }
                    //printf("%d,%s\n",__LINE__,tmp2);
                    //printf("%d,%s\n",__LINE__,tmp);
                *start = strlen(tmp2)-1;
            }            
        }
        //printf("%d,%d\n",__LINE__,*start);
    }
    return 0;
}

int main()
{
    int a=0;
    int b=0;

    char c[1024] = {0};
    char p[1024] = {0};

    if(strlen(p)>=1024||strlen(c)>=1024)
        return 1;
    while(scanf("%s%s", p, c) == 2)
    {
        Findstr(p,c,&a,&b);    
        printf("%d %d\n",a,b);
    }
    
    return 0;
}

/* 反转串 */
int revers(char *pstr)
{
    char tmp;
    char *last;
    int i = 1;
    int j = strlen(pstr);
    last = pstr+j-1;
    while(i<j)
    {
        tmp = *pstr;
        *pstr = *last;
        *last = tmp;
        i++;
        j--;
        pstr++;
        last--;
    }
    return 0;
}


发表于 2019-03-30 11:04:11 回复(0)