给定文本text和待匹配字符串pattern,二者皆只包含小写字母,并且不为空。
在text中找出匹配pattern的最短字符串,匹配指按序包含pattern,但不要求pattern连续。
如text为abaacxbcbbbbacc,pattern为cbc,text中满足条件的是abaacxbcbbbbacc下划线部分。
多行,每行一个text和一个pattern,用空格分隔。
保证1<=|text|,|pattern|<=1000,Σ|text|,Σ|pattern|<=10000。
输出最短匹配序列起止位置(位置下标从0开始),用空格分隔。若有多个答案,输出起止位置最小的答案;若无满足条件的答案,则起止均为-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; }
#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; } }暴力,多加几个限制条件,速度也很快,逻辑更简单。
#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; }
测试用例有一个卡住了……………… 题目要求的第一个字符串中含有的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; } } }
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
#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; } }
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); } } }
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)
动态规划是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); } } }
#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; } } }
#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; }