搜索+枚举字符串子串问题

来源:互联网 发布:snmp开源软件 编辑:程序博客网 时间:2024/06/05 20:09

求字符串的子串问题有两类,一种是不连续,一种是连续。

然而这两种都可以用暴力求解,不过容易 time limited exceed;

那可以只用两个for循环就get全部子串吗?


求不连续的子串:用DFS(深度优先搜索)

这里看一个题 HD 1015 Safecracker 

这个题大意就是 在给出的5-12个字符里面找到字典序最大的子串(不连续),子串字符数目是5个,且子串满足公式

v - w^2 + x^3 - y^4 + z^5 = target   (target由输入给出)

这个题要遍历所有的子串,如果一个一个找的话,要用5个for循环,如果更多呢?显然用暴力行不通。

那试试深度优先搜索(其实是递归的思想):

<span style="font-size:12px;"> #include <stdio.h> #include <iostream>  #include <string.h> #include <math.h> #define ma 15  using namespace std;  int len,num[30],bj[30]; char in[ma],ans[ma],t[ma]; int n;  void work(int k){ int sum,i; if(k==5){    sum=num[t[0]-'A']-pow(num[t[1]-'A'],2)+pow(num[t[2]-'A'],3)-pow(num[t[3]-'A'],4)+pow(num[t[4]-'A'],5);    if(sum==n&&strcmp(t,ans)>0) strcpy(ans,t);    return;    }    for(i=0;i<len;i++){ if(!bj[in[i]-'A']){  //这里要用in[i]-'A',避免重复 t[k]=in[i]; bj[in[i]-'A']=1; work(k+1);      //这里是核心,k不能写成k++,否则在回溯之后,k就不是递归之前的值了 bj[in[i]-'A']=0;//标记之后要复原 } } }  int main(){ for(int i=0;i<26;i++) num[i]=i+1;while(scanf("%d %s",&n,in)!=EOF){ if(n==0||strcmp(in,"END")==0) return 0; memset(bj,0,sizeof(bj)); memset(ans,'\0',sizeof(ans)); memset(t,'\0',sizeof(t)); len=strlen(in); work(0); if(strlen(ans)==0) printf("no solution\n"); else printf("%s\n",ans); }  return 0; }</span>

这个题是输出一个解,杭电有另一个题要求输出多个解,就要在主函数多加一个for循环。有兴趣可以练练手。

HD 1016 Prime Ring Problem

代码可以参考这个链接  :点击打开链接


求连续的子串:调用函数substr

substr函数在头文件#include<string>里面

要调用substr函数,定义字符串也要用string 定义。

substr函数:

string  s,j;

j=s.substr(i,j);  //从i的位置开始找长度为j的子串,赋给字符串j

杭电有个题可以练练手:HD 1238 Substring

题意大概是给定n个字符串,找到这n个字符串的最长子串(连续),输出最长子串的长度

上代码:

#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#define ma 105using namespace std;string a[ma];int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n;        scanf("%d",&n);        int mi=ma,bj;        for(int i=0; i<n; i++)        {            cin>>a[i];            if(a[i].size()<mi)            {                mi=a[i].size();                bj=i;            }        }        int sum=0;        for(int i=a[bj].size()-1; i>0; i--) //子串的长度,从最长的开始找        {            for(int j=0; j<=a[bj].size()-i; j++) //用substr找子串的开始位置            {                string aa,bb;                aa=a[bj].substr(j,i);                bb=aa;                reverse(bb.begin(),bb.end()); //reverse也是string头文件的函数,把字符串逆置                int k;                for(k=0; k<n; k++)                {                    if(a[k].find(aa)==a[k].npos&&a[k].find(bb)==a[k].npos)//表示没有找到与目标字符串相同的                        break;                }                if(k==n&&sum<aa.size())                    sum=aa.size();            }        }        printf("%d\n",sum);    }    return 0;}

1 0
原创粉丝点击