#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; //给定一个字符串,求出其最长的重复子串 //方法一 string lsubstr_1(const string & str) { vector<string> vs; for (int i = 0; i < str.size(); i++) vs.push_back(str.substr(i)); sort(vs.begin(), vs.end()); int max = 0; int flag = 0; for (int i = 0; i <( vs.size()-1); i++) { int j = 0; while (vs[i][j] == vs[i + 1][j] && j<vs[i].size() && j<vs[i+1].size()) j++; if (j>max) { max = j; flag = i; } } return vs[flag].substr(0, max); } //方法二 string lsubstr_2(const string & str) { string maxstr; for (int i = 0; i < str.size();i++) for (int j = (str.size() - i); j >=1 ; j--) { string subs = str.substr(i, j); int front = str.find(subs); int back = str.rfind(subs); if (front != back && subs.size() > maxstr.size()) maxstr = subs; } return maxstr; } //方法三 string lsubstr_3(const string & str) { string maxstr; for (int i = 0; i < str.size(); i++) for (int j = 0; j < i; j++) { string temp; int k = j; int m = i; while (str[m] == str[k] && i<str.size() && k<str.size()) { m++; k++; } temp = str.substr(j, k - j); if (temp.size()>maxstr.size()) maxstr = temp; } return maxstr; } void main(void) { string test; //cin >> test; getline(cin, test); cout << lsubstr_1(test) << endl; cout << lsubstr_2(test) << endl; cout << lsubstr_3(test) << endl; }
string FindStr(const string &str) { string temp, MaxStr; int MaxLen = 0; for (int i = 0; i < str.length(); ++i) { for (int j = str.length() -i; j != 0; --j) { temp = str.substr(i, j); int front = str.find(temp); int behind = str.rfind(temp); int templen = temp.length(); if (front != behind&&templen > MaxLen) { MaxStr = temp; MaxLen = templen; } } } return MaxStr; }
public class MaxReStr { public String findStr(String s){ if(s==null){ return null; } //最长重复子串的长度 int max=0; //最长重复子串的第一个字符在s中的下标 int first=0; String res = null; //i为每次循环设定的字符串比较间隔:1,2,...,s.length()-1 for(int i=1;i<s.length();i++){ for(int k=0,j=0;j<s.length()-i;j++){ if(s.charAt(j)==s.charAt(j+i)) k++; else k=0; if(k>max){ max=k; first=j-max+1; } } if(max>0){ res = s.substring(first, first+max); } } return res; } public static void main(String[] args) { // TODO Auto-generated method stub String s = "eabcdabcf"; System.out.println(new MaxReStr().findStr(s)); } }输出为 abc
#include <stdlib.h> #include <stdio.h> #define MaxChar 5000 char a[MaxChar]; char *post[MaxChar]; int pstrcmp(const void *p1, const void *p2) { return strcmp(*(char* const *)p1, *(char* const *)p2); } //求排序后相邻两个串的最长公共前缀 int common_len(char *p, char *q) { int k = 0; while(*p && (*p++ == *q++)) k++; return k; } int main() { char ch; int i = 0, j; int temp; int max = 0, max_index = 0; while((ch = getchar()) != '\n') { post[i] = &a[i];//将后缀式的指针指向该后缀式的第一个字符 a[i++] = ch; } a[i] = '\0'; qsort(post, i, sizeof(char *), pstrcmp);//对所有后缀式进行排序 for(j = 0; j < i - 1; j++) { temp = common_len(post[j], post[j+1]); if(max < temp) { max = temp; max_inde敏感词rintf("%d %s\n", max, post[max_index]); return 0; }
O(n^3)
#include <iostream> #include <string> using namespace std; int main(){ string s; cin >> s; int len = 0; for(int i = 0; i < s.size(); i++){ for(int j = s.size()-i; j >= i; j--){ string str = s.substr(i, j); int front = s.find(str); int back = s.rfind(str); if(front != back && j > len){ len = j; } } } cout << len << endl; return 0; }
string longestRepeatStr(string str) { int n = str.length(); for(int i = n - 1; i > 0; --i) for(int j = 0; j < n; ++j) { if(i + j < n) { string cur = str.substr(j,i); int index1 = str.find(cur); // 从前往后找 int index2 = str.rfind(cur); // 从后往前找 if(index1 != index2) return cur; } } }
下面说明为什么(rand7()-1)*7+rand7()可以构造出均匀分布在1-49的随机数:
首先rand7()-1得到一个离散整数集合{0,1,2,3,4,5,6},其中每个整数的出现概率都是1/7。那么(rand7()-1)*7得到一个离散整数集合A={0,7,14,21,28,35,42},其中每个整数的出现概率也都是1/7。而rand7()得到的集合B={1,2,3,4,5,6,7}中每个整数出现的概率也是1/7。显然集合A和B中任何两个元素组合可以与1-49之间的一个整数一一对应,也就是说1-49之间的任何一个数,可以唯一确定A和B中两个元素的一种组合方式,反过来也成立。由于A和B中元素可以看成是独立事件,根据独立事件的概率公式P(AB)=P(A)P(B),得到每个组合的概率是1/7*1/7=1/49。因此(rand7()-1)*7+rand7()生成的整数均匀分布在1-49之间,每个数的概率都是1/49。
程序:
int rand7()
{
int x=0;
do
{
x=(rand7()-1)*7+rand7();
}
while(x>40);
return x%10+1;
}
|
#include <iostream> #include <string> #include <cstdio> using namespace std; int main() { freopen("test.txt", "r", stdin); string str; while(cin>>str) { string maxStr; for(int i = 0; i < str.size(); i++) { for(int j = (str.size() - i); j >= 1; j--) { string subStr = str.substr(i, j); int start = str.find(subStr); int end = str.rfind(subStr); if(start + subStr.size() <= end && maxStr.size() < subStr.size()) maxStr = subStr; } } cout<<maxStr<<endl; } return 0; }
string findString( string& s ){ if( s.length() < 2 ) return s; int index = 0; string res; int maxLen = 0; int len = s.length(); for ( ; index<len-1; ++index ) { int j = index+1; while( s[index] != s[j] && j<len ) ++j; int count = 0; string tmp; if( j!=len ){ int i = index; while( s[i] == s[j] ){ ++count; tmp.push_back( s[i] ); ++i; ++j; } if( count>maxLen ){ maxLen = count; res.swap( tmp ); tmp.clear(); } } } return res; }
举例: ask not what your country can do for you ,but what you can 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
之后可以依次检测相邻两个后缀的公共长度并取出最大公共的前缀
代码:
程序输入: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)