您的位置:首页 > 其它

寻找一个字符串中连续出现次数最多的子串

2014-12-27 10:11 435 查看
一、生成后缀数组搜索

算法描述

首先获得后缀数组,然后

1.第一行第一个字符a,与第二行第一个字符b比较,不等,则

2.第一行前两个字符ab,与第三行前两个字符cb比较,不等,则

3.第一行前三个字符abc,与第四行前三个字符bcb比较,不等,则

4.第一行前四个......

上述过程就相当于在原始字符串中,

第一趟,a与b比较,ab与cb比较,abc与bcb比较,abcb与cbca比较,abcbc与bcabc比较,abcbcb与cabc比较......

第二趟,b与c比较,bc与bc比较(相等,则继续向后取长度为2的子串比较,碰到不等为止,本例中因碰到ab停止),bcb与cbc比较......

第三趟,c与b比较,cb与cb比较(相等),cbc与bca比较......

......

使用后缀数组方便编程实现



//vs2005
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <utility>
#include <string>
using namespace std;

pair<int,string> fun(const string &str)
{
	vector<string> substrs;
	int maxcount=1,count=1;
	string substr;
	int i,len=str.length();
	for(i=0;i<len;++i)
	{
		substrs.push_back(str.substr(i,len-i));
		cout<<substrs[i]<<endl;
	}
		
	for(i=0;i<len;++i)
	{
		for(int j=i+1;j<len;++j)
		{
			count=1;
			if(substrs[i].substr(0,j-i)==substrs[j].substr(0,j-i))
			{
				++count;
				for(int k=j+(j-i);k<len;k+=j-i)
				{
					if(substrs[i].substr(0,j-i)==substrs[k].substr(0,j-i))
						++count;
					else
						break;
				}
				if(count>maxcount)
				{
					maxcount=count;
					substr=substrs[i].substr(0,j-i);
				}
			}
		}
	}
	return make_pair(maxcount,substr);
}

int _tmain(int argc, _TCHAR* argv[])
{	string str;
	pair<int,string> rs;

	str="abcbcbcabc";
		rs=fun(str);
		cout<<rs.second<<':'<<rs.first<<endl;

	return 0;
}


二、优化空间复杂度

把字符串用后缀树的形式表现出来如下:

a b c a b c a b c d e .substr[0]

b c a b c a b c d e ....substr[1]

c a b c a b c d e .......substr[2]

a b c a b c d e ..........substr[3]

b c a b c d e .............substr[4]

c a b c d e ...............substr[5]

a b c d e .................substr[6]

b c d e ...................substr[7]

c d e .....................substr[8]

d e ........................substr[9]

e ..........................substr[10]

可以观察到,若存在连续出现的字串,则满足 substr[0].substr(i,j-i) == substr[j].substr(0,j-i),例如上例中的

substr[0].substr(0,3-0) == substr[3].substr(0,3-0)

我们换一种方式来看,不需要生成后缀组,但思想还是一样的。









代码:

代码中str.substr(pos2,offset)其实相当于后缀组的substr[pos2].substr(0,offset)

把字符串写成后缀组其实相当于站在不同的位置往后看这个数组,所以其实并不需要额外增加存储空间来生成后缀组。
#include <iostream>
#include <string>
using namespace std;

void main(){
    string str = "abcabcabcccccdefefefefefef";

    int len = str.length();
    int maxCount = 0;
    string longest = "";

    for(int pos1 = 0; pos1 < len; pos1++)
        for(int pos2 = pos1 + 1; pos2 < len; pos2++){
            if(str.substr(pos1,pos2-pos1) == str.substr(pos2,pos2-pos1)){
                int offset = pos2-pos1;
                int count = 2;
                for(int k = pos2 + offset; k <= len; k += offset){
                    if(str.substr(pos1,offset) == str.substr(k,offset)){
                        count += 1;
                    }else{
                        break;
                    }
                }
                if(count > maxCount){
                    maxCount = count;
                    longest = str.substr(pos1,offset);
                }
            }
        }

    cout << longest << "," << maxCount << endl;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: