zoukankan      html  css  js  c++  java
  • 最长重复子串—后缀数组

    知识点:
    1. sort 使用时得注明:using namespace std;   或直接打 std::sort()  还得加上  #include <algorithm>
    2. qort是qsort的升级版,如果能用sort尽量用sort,使用也比较简单,不像qsort还得自己去写 cmp 函数,
    只要注明  使用的库函数就可以使用,参数只有两个(如果是普通用法)头指针和尾指针; 


    3. 默认sort排序后是升序,如果想让他降序排列,可以使用自己编的cmp函数


    bool compare(int a,int b){
     return a>b; //降序排列,如果改为return a<b,则为升序
    }
    sort(*a,*b,cmp);


    4. compare 函数中对于double需要特别注意返回值的问题,
    显然cmp返回的是一个整型,所以避免double返回小数而被丢失。


    int cmp( const void *a , const void *b ){
    return *(double *)a > *(double *)b ? 1 : -1;

    }


    分析:要求输出它及其首字符的位置。 例如字符串yyabcdabjcabceg,输出结果应该是abc和3。

      1.可以将上面字符串分解为,后缀数组形式。
    substrs[0] =yyabcdabjcabceg;
    substrs[1] =yabcdabjcabceg;
    substrs[2] =abcdabjcabceg;
    substrs[3] =bcdabjcabceg;
    substrs[4] =cdabjcabceg;
    substrs[5] =dabjcabceg;
    substrs[6] =abjcabceg;
    substrs[7] =bjcabceg;
    substrs[8] =jcabceg;
    substrs[9] =cabceg;
    substrs[10]=abceg;
    substrs[11]=bceg;
    substrs[12]=ceg;
    substrs[13]=eg;
    substrs[14]=g;

      2.对这些字符串按照字典顺序排序,

      3.然后比较相邻字符串的前驱,找到最长的匹配项。


    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    pair<int, string> fun(const string &str)
    {
    	vector<string> substrs;
    	int maxcount = 1;
    	unsigned int count = 0;
    	string substr;
    	int i, len = str.length();
     
    	for (i = 0; i < len; i++)   // 得到所有的后缀子串
    	{
    		// basic_string substr(size_type pos = 0,size_type n = npos) const;
    		// 从pos开始,截取n个字符组成的字符串。
    		substrs.push_back(str.substr(i, len-i));
    	}
    	
    	// 后缀树排序
    	sort(substrs.begin(), substrs.end());
    
    	// 比较相邻两个字符串公共序列
    	string str1;
    	string str2;
    	vector<string>::iterator iter;
    	for(iter = substrs.begin(); iter != substrs.end()-1; ){
    		count = 0;
    		str1 = *iter++;
    		str2 = *iter;
    		
    		while(	count < str1.length() &&  count < str2.length()  &&  (str1.at(count) == str2.at(count))	)
    			count++;
    
    
    		if(count > maxcount){
    			maxcount = count;
    			substr = str1.substr(0, maxcount);
    		}
    			
    	}
    
    	substrs.clear();
    	return make_pair(maxcount,substr);
    }
    
    int main()
    {
    	string str;
    	pair<int, string> rs;
    	while (cin >> str)
    	{
    		rs = fun(str);
    		cout << rs.second << ':' << rs.first << endl;
    	}
    	return 0;
    }
    

    下面是另一种解题思路:
    时间复杂度比上面介绍的要高,但是空间复杂度为O(1).时间换空间。
    思路:对源字符串所有后缀的所有子串,从每一个后缀的最长子串开始,
    分别从前向和后向开始在源字符串中查找匹配的子串,
    若两次查找位置不一致则说明存在重复的长度最长的字串,并返回前向查找时的位置。
    e.g. string = “abcedfghiabckl‘,当使用子串”abc“在源字符串中分别前向和后向匹配时,

    找到的位置分别为pos1=0, pos2 = 9.

    #include <iostream>
    #include <string>
    using namespace std;
    int main()
    {
    	string str,tep;
    	cin>>str;
    	cout<<"length=="<<str.length()<<endl;
    	for (int i = str.length()-1; i>=1; i--)
    	{
    		for (int j = 0; j < str.length(); j++)
    		{
    			// 如果没有这句的约束,那么结果错误。
    			// 这句话使得每次得到的tep的长度是i,即满足从大到小取字符串。
    			if (j + i <= str.length())
    			{
    				size_t t = 0;
    				size_t num = 0;
    				tep = str.substr(j, i); // 从大到小取字串。i是截取的字符串的长度,先截取最长的,再截取次长的
    				t = str.find(tep);		// 正序查找
    				num = str.rfind(tep);	// 逆序查找
    				// 如果两次查找的位置不一样,说明存在重复字串。
    				if (t != num)			// 满足条件就输出,因为是从最长的字符串开始截取。
    				{
    					cout<<tep<<" "<<t<<endl;
    					return 0;
    				}
    			}
    		}
    	}
    	return 0;
    }

  • 相关阅读:
    二分查找(Binary Search)的几种变种形式
    深入理解jvm虚拟机读书笔记-垃圾收集器与内存分配策略(二)
    深入理解jvm虚拟机读书笔记-垃圾收集器与内存分配策略(一)
    Java8函数式编程
    Spring DBUnit 插入数据的时候如何处理自增ID
    IDEA Debug 技巧总结
    声明
    Mybatis最详细笔记
    关于jdbc概述
    SpringAOP(动态代理)
  • 原文地址:https://www.cnblogs.com/sjw1357/p/3863992.html
Copyright © 2011-2022 走看看