zoukankan      html  css  js  c++  java
  • 给定一个字符串,输出最长的重复子序列

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

    举例: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

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

    代码:

    [cpp] view plaincopyprint?

    1. /*给定出一个字符串,输出最长的重复子字符串*/
    2. #include <iostream>
    3. #include <algorithm>
    4. #include <string>
    5. using namespace std; 
    6. const int MaxCharNum = 5000000; 
    7. bool StrCmp(char* str1,char* str2); 
    8. void GenSuffixArray(char* str,char* suffixStr[]); 
    9. int ComStrLen(char* str1,char* str2); 
    10. void GenMaxReStr(char* str);  
    11. int main() 
    12. char str[MaxCharNum]; 
    13.     cin.getline(str,MaxCharNum);//遇到回车结束
    14.     GenMaxReStr(str); 
    15.     system("pause"); 
    16. return 1; 
    17. void GenMaxReStr(char* str) 
    18. int len = strlen(str); 
    19. int comReStrLen = 0; 
    20. int maxLoc = 0; 
    21. int maxLen = 0; 
    22. char* suffixStr[MaxCharNum]; 
    23.     GenSuffixArray(str,suffixStr);//产生后缀数组
    24. //对后缀数组进行排序
    25.     sort(suffixStr,suffixStr+len,StrCmp); 
    26. //统计相邻单词中相同的字符数,并输出结果
    27. for (int i = 0;i < len-1;i++ ) 
    28.     { 
    29.         comReStrLen =  ComStrLen(suffixStr[i],suffixStr[i+1]); 
    30. if (comReStrLen > maxLen) 
    31.         { 
    32.             maxLoc = i; 
    33.             maxLen = comReStrLen; 
    34.         } 
    35.     } 
    36. //输出结果
    37. for (int i = 0;i < maxLen;i++) 
    38.     { 
    39.         cout<<suffixStr[maxLoc][i]; 
    40.     } 
    41.     cout<<endl; 
    42. /*为字符串产生其后缀数组,并存放到数组suffixStr中*/
    43. void GenSuffixArray(char* str,char* suffixStr[]) 
    44. int len = strlen(str); 
    45. for (int i = 0;i < len;i++) 
    46.     { 
    47.         suffixStr[i] = &str[i]; 
    48.     } 
    49. /*返回str1和str2的共同前缀的长度*/
    50. int ComStrLen(char* str1,char* str2) 
    51. int comLen = 0; 
    52. while(*str1 && *str2) 
    53.     { 
    54. if (*str1 == *str2) 
    55.         { 
    56.             comLen++; 
    57.         } 
    58.         str1++; 
    59.         str2++; 
    60.     } 
    61. return comLen; 
    62. //字符串升序排序
    63. bool StrCmp(char* str1,char* str2) 
    64. if (strcmp(str1,str2) >=0 ) 
    65.     { 
    66. return false; 
    67.     } 
    68. return true; 
    /*给定出一个字符串,输出最长的重复子字符串*/
    #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;
    }

    程序输入:ask not what your country can do for you,but what you can do for your country

    输出:can do for you

    时间复杂度分析:产生后缀数组-时间复杂度O(N)、对后缀数组排序是O(N*NlogN),第一个N表示字符串的比较,后面NlogN使用快排排序。依次检测相邻两个后缀的公共长度-时间复杂度O(N*N)、取出最大公共长度的前缀-时间复杂度O(N)。

    总的时间复杂度是O(N*NlogN)

    这里使用系统函数sort和strcmp生成有序的后缀数组,他们没有充分的利用数组重复的特性

    我们可以使用倍增算法高效的产生排好序的后缀数组,从而提高效率

  • 相关阅读:
    一道关于js声明变量,var和let的面试题
    自执行匿名函数: (function() { /* code */ })();
    2017-09-26 开通博客第一天。 希望以后能够坚持更新,记录自己的成长,努力汲取各位朋友的知识见解。
    mybatis中根据日期模糊查询
    <![CDATA[文本内容]]>
    mybatis中sql标签和include标签
    Redis 安装
    Redis 简介
    从尾到头打印链表
    替换空格
  • 原文地址:https://www.cnblogs.com/yoyov5123/p/3051427.html
Copyright © 2011-2022 走看看