字符串的最大子串问题

基于字符串的最大子串问题是经常面试的问题,想要表现的好不但要会基础的方法,同时还要学会优化的算法。

常考的有两个问题:

1:两个字符串的最大公共子串(还可能是子序列)

2:同一个字符串中相同的最大子串问题

例如输入qweabcuwabcfw,输出结果为:重复字符串的长度3和位置4

一:求两个字符串的最大公共子串


#include<iostream>
#include<string.h>
#include<vector>
using namespace std;
char out[50];
vector<string> re;

int longestSubstring1(string x, string y,int &start) {
    int xlen = x.size();
    int ylen = y.size();
    if (xlen == 0 || ylen == 0) {
        return 0;   
    }
    int max = -1;
    //暴力**法,两重for循环加 while
    for (int i = 0; i < xlen; i++) {
        for (int j = 0; j < ylen; j++) {
            int m = i, n = j;
            int len = 0;
            while (m < xlen && n < ylen) {
                if (x[m] != y[n]) {
                    break;
                }
                m++;
                n++;
                len++;
            }
            if (len > max) {
                max = len;
                start = i;
            }
        }
    }
    return max;
}
//动态规划
int longestSubstring2(string x, string y,int &start) {
   //设置dp数组
   vector<vector<int> > f(x.size() + 1, vector<int>(y.size() + 1, 0));
   //vector< vector<int> > f;
   int max = -1;
   for (int i = 1; i <= x.size(); i++) {
       for (int j = 1; j <= y.size(); j++) {
           if (x[i - 1] != y[j - 1]) f[i][j] = 0;
           else if (x[i - 1] == y[j - 1]) f[i][j] = f[i - 1][j - 1] + 1;
           if (max < f[i][j]) {
             max = f[i][j];
             start = i;
           }
       }
    }
    return max;
}


int main()
{
    string x = "adbccadbxadebbca";
    string y = "bcadrbxad";
    int start;
    int out =longestSubstring1 (x,y,start);
    cout << out << "-" << start << endl;
    for (int i=0; i<out ;++i)
    cout << x[start + i];
    cout << endl;
    
    cout << longestSubstring2(x,y,start) <<"-" << start;
    
return 0;

}

字符串的最大子串问题

2:c语言的写法

#include<iostream>
#include<string.h>
#include<vector>
using namespace std;
char out[50];
vector<int> myvector;
int fun(char* a , char *b)
 {
  int len_a = strlen(a);
  int len_b = strlen(b);
    if(len_a<=0||len_b<=0)
        return -1;
    char * c , *d;
    if(len_a<len_b)
    {
     c = b;
     d = a;
    }
     else
     {
         c =a ;
         d =b;
     }
    int max =0; 
  for( ; *c!='\0';c++ )
  {
      int n = 0; //n是个遍历指针,判断首字母是否相等
      for( ;*(d+n)!='\0'; ++n)
      {
       if(*c !=*(d+n))
       {
        continue;
       }
       else
       {
           int len =0;
           while(*(c+len)!='\0'&&*(c+len)==*(d+n+len)&&*(d+n+len)!='\0')
           {
           len++;
           }
           if(len>max)
           {
              max =len;
           {
                   for( int m=0;m <max;m++)  
                    {  
                        out[m]=*(c+m);  
                    }  
                    out[max]='\0';
           }
           }
    
       }
                    
      }     
       
  }
    
    return max;
 }

int main()
{
    char a[] ="adbccadbxadebbca";
    char b[]= "bcadrbxad";
    int len =fun(a,b);
    
    cout << out << endl;
    //cout << 0;
return 0;

}

还有别人的一个递归的解法,没看太懂,贴出来你们欣赏吧!

#include <iostream>
#include <string>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
//#include <windows.h>
using namespace std;


char findMaxStr(char * s1,char *s2){
    char *ss;
    static int maxlen=0;
    int len;
    if(strstr(s1,s2))  //如果S2是S1的子串
    {
        if(maxlen<strlen(s2))
        {
            maxlen=strlen(s2);
            printf("maxlen:%d result:%s\n",maxlen,s2);
        }
        return 0;
    }
    len=strlen(s2);
    if(len==1)
    {    //递归的出口函数,终止条件
        //printf("error\n");
        //return 1;
        return 1;
    }
    ss=(char *)malloc(len);
    memcpy(ss,s2,len);//内存拷贝函数
    ss[len-1]=0;
    //printf("len=%d str=%s\n",len-1,ss);
    findMaxStr(s1,ss); //是否需要注释掉??
    memcpy(ss,s2+1,len); //后移一位
    //printf("second: len=%d str=%s\n",len-1,ss);
    findMaxStr(s1,ss); //递归
    free(ss);
    return 1;
}

int main() 
{
    char a[200]="adcyioabcdefxxabcdxxx";
    char b[200]="mxx0";


    findMaxStr(a,b);
    return 0;
}

二:字符串的最长公共子串

这实质上是第一道题的变形,例如输入qweabcuwabcfw,输出结果为:重复字符串的长度3和位置4

 

第一种解法:以字符串的长度为外循环,内循环从字符串的第一个元素开始向后移动。

#include<iostream>
#include<string>
using namespace std;
int main()
{
string str, tep;
cout << "输入字符串" << endl;
cin >> str;
cout <<str.size()<<endl;
int mysize = str.size();
    int k =0;
    int max =0;
    int first;
for (int i = 1; i <mysize; i++)
{
for (int j = 0; j < mysize-i; j++)
{
    if (str[j]==str[j+i])
    {
        k++;
    }
    else
    {
        k=0;
    }
    if(k>max)
   {
     max = k;
     first =i-k+1;
    }
}
}
    cout << first << "-" << max <<endl;
return 0;

}

第二种解法

 

题目:输入一行字符串。找出当中出现的同样且长度最长的字符串,输出它及其首字符的位置。

               比如:“yyabcdabjcabceg",输出结果应该为abc 和3.

字符串的最大子串问题

#include<iostream>
#include<string>
using namespace std;
int main()
{
string str, tep;
cout << "输入字符串" << endl;
cin >> str;
for (int i = str.length() - 1; i > 1; i--)
{
for (int j = 0; j < str.length(); j++)
{
if (j + i <= str.length())
{
size_t t = 0;
size_t num = 0;
tep = str.substr(j, i);//从大到小取子串,从j位置开始取长度为i的子串
t = str.find(tep);//正序查找
num = str.rfind(tep);//逆序查找
if (t != num)//假设两次查找位置不一致,说明存在反复子串
{
cout << tep << " " << t + 1 << endl;//输出子串及位置
system("pause");
return 0;


}
}
}
}
}
substr(j, i);//从大到小取子串,从j位置开始取长度为i的子串
t = str.find(tep);//正序查找
num = str.rfind(tep);//逆序查找
if (t != num)//假设两次查找位置不一致,说明存在反复子串
{
cout << tep << " " << t + 1 << endl;//输出子串及位置
system("pause");
return 0;


}
}
}
}
}