当前位置:编程学习 > 网站相关 >>

XMU 1431 字符串的运算 字符串的的次方中的子串中找 目标串

1431.字符串的运算
Time Limit: 1500 MS         Memory Limit: 65536 K
Total Submissions: 137 (36 users)         Accepted: 36 (26 users)

Description
我们对字符串 S 做了以下定义:
1. S ^ k表示由k个字符串S构成的新字符串。 例如, S = "abc", k = 3, 则S ^ k  =  "abcabcabc"
2. Subsequence(S) 表示由字符串S的所有非空子序列构成的字符串集合。例如, S = "abc", 则Subsequence(S) = {"a", "b", "c", "ab", "ac", "bc", "abc"}
现在, 给你2个字符串S和T, 希望你能找到最小的k, 满足T ∈Subsequence(S ^ k)


Input
输入只有2行, 分别为字符串S和T (1 <= |S|, |T| <= 100,000), 输入保证字符串S和T只由小写字母构成。


Output
输出最小的k, 满足T ∈Subsequence(S ^ k), 若不存在这样的k, 则输出-1


Sample Input
abc
abacbc


Sample Output
3


Source
doraemon @ xmu
[ Submit] [ Statistic] [ Status ] [ Discuss]
All Copyright Reserved 2007 Xiang Guangte, Zheng Le
Xmu.Csd All Rights Reserved.


/*以下解题报告来自同学 不是我搞的 

题目:字符串的运算
  题目大意:
我们对字符串 S 做了以下定义:
1. S ^ k表示由k个字符串S构成的新字符串。 例如, S = "abc", k = 3, 则S ^ k  =  "abcabcabc"
2. Subsequence(S) 表示由字符串S的所有非空子序列构成的字符串集合。例如, S = "abc",
则Subsequence(S) = {"a", "b", "c", "ab", "ac", "bc", "abc"}
现在, 给你2个字符串S和T, 希望你能找到最小的k, 满足T ∈Subsequence(S ^ k)


解题思路:Subsequence(S)就是从S中选一些字符保持相对顺序不变组成的非空字符串;


  现在我们要把T分成K份这样的字符串,K越小越好,于是策略就是:先令k=0,在串S中找串T,从串T的第一个字符找起
  遇到了第一个字符再找第二个字符,一直找到不能找为止,然后k++,然后我们又返回到S串的开始位置继续找,直到把
  T中的所有字符都找完,最后的答案就是k,如果T中出现了S中没有的字符,那么这个字符是永远找不到的,最后答案就是-1;


  但是暴力枚举S串的下标时间复杂度是O(N^2),会超时,如果可以在S中找T的字符时快速定位,这样就不会超时了,因此
  可以先预处理一下S串,建立S串中每个字符的在S中出现的序列,比如字符'a'在S串中1,3,5位置出现过,那么字符'a'的序列
  就是(1,3,5)。有了这个序列后我们就可以快速定位一个我们想找的字符了,比如现在在S的i位置,我要找的下一个字符是
  'a',那么我们就用i+1下标在字符'a'的序列中二分找到最接近下标,如果没有我们就直接返回S串的开始位置,继续用上述的
  方法,这样时间复杂度就是降为O(N*log(N))。
*/

 


[cpp]
#include<stdio.h>  
#include<string.h>  
#include<set>  
using namespace std; 
int vis[30]; 
char s[110000],t[110000]; 
int find(int n,int m) 

    int i,j=0,k=0,b; 
    set <int> next[30]; 
    set <int> ::iterator it; 
    memset(vis,0,sizeof(vis)); 
    for(i=0;i<n;i++) 
        vis[s[i]-'a']=1,next[s[i]-'a'].insert(i); 
    for(i=0;i<m;i++) if(!vis[t[i]-'a']) return -1; 
    i=0; 
    /*
    abc                    n=3
    abacbc                 m=6
    */ 
    while(j<m) 
    { 
        while(j<m) 
        { 
            b=t[j]-'a'; 
            it=next[b].lower_bound(i);//next里面存的是数组的下标  
            /*函数lower_bound()在first和last中的前闭后开区间进行二分查找,
            返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置*/ 
            if(it==next[b].end())//没有找到比i大的下一个b的话    
            { 
                if(i==0) return -1;//如果从第1个开始找都木有找到b字符那说明不存在   
                i=0; break;//没有找到比i大的下一个b 新增加一个s串从开头继续找  
            } 
            else i=(*it)+1,j++;//i前进到 *it对应的下标的下一个  
        } 
        k++; 
    } 
    return k; 

int main() 

    int i,j,n,m,flag; 
    while(scanf("%s%s",s,t)!=EOF) 
    { 
        n=strlen(s); 
        m=strlen(t); 
        printf("%d\n",find(n,m)); 
    } 
    return 0; 

#include<stdio.h>
#include<string.h>
#include<set>
using namespace std;
int vis[30];
char s[110000],t[110000];
int find(int n,int m)
{
    int i,j=0,k=0,b;
    set <int> next[30];
    set <int> ::iterator it;
    memset(vis,0,sizeof(vis));
    for(i=0;i<n;i++)
        vis[s[i]-'a']=1,next[s[i]-'a'].insert(i);
    for(i=0;i<m;i++) if(!vis[t[i]-'a']) return -1;
    i=0;
    /*
    abc                    n=3
    abacbc                 m=6
    */
    while(j<m)
    {
        while(j<m)
        {
            b=t[j]-'a';
            it=next[b].lower_bound(i);//next里面存的是数组的下标
            /*函数lower_bound()在first和last中的前闭后开区间进行二分查找,
            返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置*/
          &nb

补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,