• 字符串相关面试题(整理)


    1. 题目:输入一个字符串,要求找出字符串中最大子串的长度(如字符串abcd13agbf,当重复出现某个字符时,算一个子串,比如abcd13abcd13agb都是子串)

     理解:要是每个字符都不一样,则最大子串长度为0

     思想:用空间换取时间,用一个数组lastPos[256]代表着256个可能的字符(ASC2码),而数组的值代表字符串中这个字符的最后出现位置,初始数组元素都为负数,然后每次取字符串中的一个字符,此字符的ASC2码为c,若lastPos[c]<0,则表示此字符第一次出现,置lastPos[c]为此字符在字符串中的位置,若lastPos[c]>=0,则表示此字符已经出现过,则可以计算这个子串的长度,若比之前的最大子串长,则更新最大子串长度。

     分析:时间复杂度为on遍历一次即可

     

    int GetMaxSubStr(const unsigned char *str)
    
    {
    
        int maxLen = 0; 
    
        if (NULL == str)
    
           return 0;
    
        int lastPos[256]; //代表着256个可能的字符(ASC2码),数组元素值代表字符串中字符的最后出现的位置
    
        for (int i = 0; i < 256; ++i)
    
            lastPos[i] = -1;
    
        for (int pos = 0; str[pos] != ''; ++pos)
    
        {
    
            unsigned char c = str[pos]; 
    
            if (lastPos[c] > -1) //此字符已经出现过
    
            {
    
                int len = pos - lastPos[c] + 1; //计算子串的长度
    
                if (len > maxLen) 
    
                   maxLen = len;
    
            }
    
            lastPos[c] = pos;
    
        }
    
        return maxLen;
    
    }  
    

      

    2. 找出两个字符串中的最长相同子串

    算法的思想:利用二维数组建立两个字串之间的“对应矩阵”,然后初始化矩阵(mat[i][j]10),然后根据矩阵的对角线找出连续出现1的最长段,及在串中的起始位置。

    如果只有两个字符串,可以先建一个二维数组(实际上用不到二维数组,下面再详细说),如inputreputation,如下:   
          i   n   p   u   t   
      r   0   0   0   0   0   
      e   0   0   0   0   0   
      p   0   0   1   0   0   
      u   0   0   0   2   0   
      t   0   0   0   0   3   
      a   0   0   0   0   0   
      t   0   0   0   0   1   
      i   1   0   0   0   0   
      o   0   0   0   0   0   
      n   0   1   0   0   0   
      其中的数字含义如下,0表示相应行和列的字符不相等,不是零就表示从这个字符开始,前n个字符是相同的,n就是那个数。比如第5列,第5行是3,表示inputreputation都有put这个子串。这些数里边有一个最大的,找出来就是了。

    所以可以看出,对于两个字符串的问题,如果你不是想把所有的最长公共子串都找出来的话,可以逐行逐列地计算,只要在计算过程中保留最大值就可以了。   

    怎么"逐行逐列"地计算呢?可以先算第一行第一列,然后每一行每一列都通过上一行上一列算出。如果两个字符不相等,就为零。如果相等,就是左上角的数+1。因此算出了下一行和下一列,上一行和上一列就可以不要了。因为我们纵保存最大值,和产生最大值的位置。所谓动态规划,就是你算出下一行下一列,上一行上一列就可以不要了。

    动态规划

    private void printLCS(StringBuffer sb, int i, int j, String s1, int[][] flag) {
    
    if (i == 0 || j == 0) {
    
    return;
    
    }
    
    if (flag[i][j] == 1) {
    
    printLCS(sb, i - 1, j - 1, s1, flag);
    
    sb.append(s1.charAt(i - 1));
    
    } else if (flag[i][j] == 2) {
    
    printLCS(sb, i - 1, j, s1, flag);
    
    } else {
    
    printLCS(sb, i, j - 1, s1, flag);
    
    }
    
    }
    
     public String calculateLCS(String s1, String s2) {
    
     int[][] result = new int[s1.length() + 1][s2.length() + 1];
    
    int[][] flag = new int[s1.length() + 1][s2.length() + 1];
    
    for (int i = 0; i <= s1.length(); i++) {
    
    result[i][0] = 0;
    
    }
    
    for (int i = 0; i <= s2.length(); i++) {
    
    result[0][i] = 0;
    
    }
    
    for (int i = 1; i <= s1.length(); i++) {
    
    for (int j = 1; j <= s2.length(); j++) {
    
    if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
    
    result[i][j] = result[i - 1][j - 1] + 1;
    
    flag[i][j] = 1;
    
    } else if (result[i - 1][j] >= result[i][j - 1]) {
    
    result[i][j] = result[i - 1][j];
    
    flag[i][j] = 2;
    
    } else {
    
    result[i][j] = result[i][j - 1];
    
    flag[i][j] = 3;
    
    }
    
    }
    
    }
    
     
    
    StringBuffer sb = new StringBuffer();
    
    printLCS(sb, s1.length(), s2.length(), s1, flag);
    
    String lcs = sb.toString();
    
    return lcs;
    
     
    
    }
    
     
    
    public static void main(String[] args) {
    
    String s1 = "ssssssssssssssssssssssssssssssss";
    
    String s2 = "111sssss11ss";
    
    LCS lcs = new LCS();
    
    System.out.print(lcs.calculateLCS(s1, s2));
    
    }
    
     
    
    }
    

      

     

    3. 在一个字符串中查找可能的最长子串,该子串由相同字符组成

     

    #include <stdio.h>
    #include <string.h>
    void find(char* str, char*& start, int& length)
    
    {
    
        char* p = str;
    
        char* q;
    
        int len = 0;
    
        length=0;
    
        while(*p)
    
        {
    
            q = p+1;
    
            while(*q && *q == *p)
    
                q++;
    
            len = q - p;
    
            if(len>length)
    
            {
    
                length = len;
    
                start = p;
    
            }
    
            p=q;
    
        }
    
    }
    
     
    
    int main()
    
    {
    
        char str[1024];
    
        scanf("%s", str);
    
        char* p;
    
        int len;
    
        find(str,p, len);
    
        
    
        p[len]=0;
    
        printf("%s
    ", p);
    
        
    
        return 0;
    
    }
    

      

    4. 给定一个字符串,输出最长的重复子序列

    举例:ask not what your country can do for you,but what youcan do for your country

    最长的重复子序列:can do for you

    思路:使用后缀数组解决

    分析:

    1、由于要求最长公共子序列,则需要找到字符串的所有子序列,即通过产生字符串的后缀数组实现。

    2、由于要求最长的重复子序列,则需要对所有子序列进行排序,这样可以把相同的字符串排在一起。

    3比较相邻字符串,找出两个子串中,相同的字符的个数。

    注意,对于一个子串,一个与其重复最多的字符串肯定是紧挨着自己的两个字符串。

    步骤:

          1、对待处理的字符串产生后缀数组

          2对后缀数组排序

          3、依次检测相邻两个后缀的公共长度

          4取出最大公共长度的前缀

    举例:输入字符串 banana

    1、字符串产生的后缀数组:
        a[0]:banana
        a[1]:anana
        a[2]:nana
        a[3]:ana
        a[4]:na
        a[5]:a

    2、对后缀数组进行快速排序,以将后缀相近的(变位词)子串集中在一起

        a[0]:a
        a[1]:ana
        a[2]:anana
        a[3]:banana
        a[4]:na
        a[5]:nana

    之后可以依次检测相邻两个后缀的公共长度并取出最大公共的前缀

    代码:

    /*给定出一个字符串,输出最长的重复子字符串*/
    
    #include <iostream>
    
    #include <algorithm>
    
    #include <string>
    
    using namespace std;
    
    const int MaxCharNum = 5000000;
    
     
    
    bool StrCmp(char* str1,char* str2);
    
    void GenSuffixArray(char* str,char* suffixStr[]);
    
    int ComStrLen(char* str1,char* str2);
    
    void GenMaxReStr(char* str); 
    
     
    
    int main()
    
    {
    
    char str[MaxCharNum];
    
    cin.getline(str,MaxCharNum);//遇到回车结束
    
    GenMaxReStr(str);
    
    system("pause");
    
    return 1;
    
    }
    
     
    
    void GenMaxReStr(char* str)
    
    {
    
    int len = strlen(str);
    
    int comReStrLen = 0;
    
    int maxLoc = 0;
    
    int maxLen = 0;
    
    char* suffixStr[MaxCharNum];
    
    GenSuffixArray(str,suffixStr);//产生后缀数组
    
    //对后缀数组进行排序
    
    sort(suffixStr,suffixStr+len,StrCmp);
    
     
    
    //统计相邻单词中相同的字符数,并输出结果
    
    for (int i = 0;i < len-1;i++ )
    
    {
    
    comReStrLen =  ComStrLen(suffixStr[i],suffixStr[i+1]);
    
    if (comReStrLen > maxLen)
    
    {
    
    maxLoc = i;
    
    maxLen = comReStrLen;
    
    }
    
    }
    
    //输出结果
    
    for (int i = 0;i < maxLen;i++)
    
    {
    
    cout<<suffixStr[maxLoc][i];
    
    }
    
    cout<<endl;
    
    }
    
    /*为字符串产生其后缀数组,并存放到数组suffixStr中*/
    
    void GenSuffixArray(char* str,char* suffixStr[])
    
    {
    
    int len = strlen(str);
    
    for (int i = 0;i < len;i++)
    
    {
    
    suffixStr[i] = &str[i];
    
    }
    
    }
    
    /*返回str1和str2的共同前缀的长度*/
    
    int ComStrLen(char* str1,char* str2)
    
    {
    
    int comLen = 0;
    
    while(*str1 && *str2)
    
    {
    
    if (*str1 == *str2)
    
    {
    
    comLen++;
    
    }
    
    str1++;
    
    str2++;
    
    }
    
    return comLen;
    
    }
    
     
    
    //字符串升序排序
    
    bool StrCmp(char* str1,char* str2)
    
    {
    
    if (strcmp(str1,str2) >=0 )
    
    {
    
    return false;
    
    }
    
    return true;
    
    }
    

      

    计划、执行、每天高效的活着学着
  • 相关阅读:
    BZOJ 3505: [Cqoi2014]数三角形 数学
    BZOJ 3931: [CQOI2015]网络吞吐量 最大流
    BZOJ 4236: JOIOJI MAP
    BZOJ 4247 挂饰 背包DP
    hihocoder #1224 : 赛车 dfs
    hihocoder #1223 : 不等式 水题
    BZOJ 3224: Tyvj 1728 普通平衡树 treap
    uoj #31. 【UR #2】猪猪侠再战括号序列 贪心
    BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数
    心跳回忆4 攻略
  • 原文地址:https://www.cnblogs.com/huxiaoyun90/p/3315723.html
Copyright © 2020-2023  润新知