最长公共重复不重复子串系列问题
1.求一个字符串中连续出现的次数最多的子串
例如字符串“abababc”,最多连续出现的为ab,连续出现三次。
http://blog.csdn.net/ysu108/article/details/7795479
分析:
后缀数组arr[i= 0àstrlen(s) -1]
abababc
bababc
ababc
babc
abc
bc
c
可以看出第一个后缀数组和第三个后缀数组的起始都为ab,第5个后缀数组也为ab。可以看出规律来,一个字符串s,如果第一次出现在后缀数组i的前面,那么如果它重复出现,下一次出现应该在第i+len(s)个后缀数组的前面。
Eg:
intcon_sub(char *str, char**ret)
{
int max_time = 0;//连续出现的最多次数
int ret_len = 0;//连续出现的字符串的长度
char *addr = NULL;//连续出现字符串的起始地址
int len = strlen(str);
char **a = (char**)malloc(sizeof(char*)*len);
//生成后缀数组
for(inti=0; i a[i] = &str[i]; //---重复字符串的长度---范围为到(len+1)/2 for(inti=1; i<=(len+1)/2; i++) { //当重复的字符串长度为i的时候,如果是连续出现的,那么第j和第j+i个后缀数组前面为重复的字符串 for(int j=0;j+i<=len-1;j++) { int k = j; int temp_time = 1; //key:第j和第j+i个后缀数组前面的i个字符组成的子串为重复的字符串 while(k+i <= len-1 && strncmp(a[k], a[k+i], i) == 0) { temp_time++;//重复次数 k += i; } if(temp_time > max_time) { max_time =temp_time; ret_len = i; addr = a[k]; } } } *ret= new char[ret_len+1]; strncpy(*ret,addr, ret_len); *(*ret+ret_len)= '\0';//返回重复的子字符串 return max_time;//返回重复次数 } 2.求一个字符串中的最长重复子串 还是上面的字符串,那么最长的重复子串为abab http://blog.csdn.net/hackbuteer1/article/details/7968623 对一个字符串生成相应的后缀数组后,然后再排序,排完序依次检测相邻的两个字符串的开头公共部分,以便找出最长的重复子串。 Eg: 如若输入字符串为"banana",该数组将表示这些后缀: a[0]:banana a[1]:anana a[2]:nana a[3]:ana a[4]:na a[5]:a 由于数组a中的指针分别指向字符串中的每个后缀,所以将数组a命名为"后缀数组" 第二、对后缀数组进行快速排序,以将后缀相近的(变位词)子串集中在一起 qsort(a, n, sizeof(char*), pstrcmp)后 a[0]:a a[1]:ana a[2]:anana a[3]:banana a[4]:na a[5]:nana 第三、使用以下comlen函数对数组进行扫描比较邻接元素,以找出最长重复的字符串: for(i = 0 ; i < n-1 ; ++i ) { temp=comlen( a[i], a[i+1] ); if( temp>maxlen ) { maxlen=temp; maxi=i; } } printf("%.*s\n",maxlen, a[maxi]); int comlen( char *p, char *q ) { int i = 0; while( *p && (*p++ == *q++) ) ++i; return i; } 3. 最长公共子串 http://blog.csdn.net/hackbuteer1/article/details/6686931 方法1:动态规划 方法2:将字符串s1和s2分别写在两把直尺上面(我依然用s1,s2来表示这两把直尺),然后将s1固定,s2的头部和s1的尾部对齐,然后逐渐移动直尺s2,比较重叠部分的字符串中的公共子串的长度,直到直尺s2的尾部移动到s1的头部。在这个过程中求得的最大长度就是s1、s2最大子串的长度。 eg: int textquery(string query, string text) { inti,len_q,len_t; intds,tmp,max_len = 0; ints1begin,s2begin; len_q= query.size(); len_t= text.size(); for(i= 0 ; i < len_q + len_t ; i++) { s1begin= s2begin = 0; if(i< len_q) s1begin= len_q - i; else s2begin= i - len_q; tmp= 0; ds= 0; while(1) { if(s1begin>= len_q -ds || s2begin >= len_t-ds) break; if(query[s1begin+ds]!=text[s2begin+ds]) { max_len= tmp>max_len?tmp:max_len; tmp= 0; } else tmp++; ds++; } max_len= tmp>max_len?tmp:max_len; } returnmax_len; } 4. 求字符串中最长无重复字符的子串 http://blog.csdn.net/luxiaoxun/article/details/8036544 对这个字符串构造后缀数组,在每个后缀数组中,寻找没有重复字符的最长前缀,最长的前缀就是要找的子串。 //得到字符串最长的无重复的前缀长度 int longestlen(char * p) { int hash[256]; int len = 0; memset(hash,0,sizeof(hash)); while (*p &&!hash[*p]) { hash[*p] = 1; ++ len; ++ p; } return len; } //使用后缀数组解法 int max_unique_substring4(char * str) { int maxlen = -1; int begin = 0; char *a[99999]; int n = 0; while(*str != '\0') { a[n++] = str++; } for (int i=0; i { int temlen = longestlen(a[i]); if (temlen > maxlen) { maxlen = temlen; begin = i; } } printf("%.*s\n", maxlen,a[begin]); return maxlen; } 5. 后缀数组--处理字符串的利器 http://blog.csdn.net/luxiaoxun/article/details/8041155 6.最长回文子串(最长对称子字符串) 这个算法思想其实很简单啊,时间复杂度为O(N2),空间复杂度仅为O(1)。就是对给定的字符串S,分别以该字符串S中的每一个字符C为中心,向两边扩展,记录下以字符C为中心的回文子串的长度。但是有一点需要注意的是,回文的情况可能是 a ba,也可能是 a b b a。 string expandAroundCenter(string s, int c1,int c2) { intl = c1, r = c2; intn = s.length(); while (l >= 0 && r <= n-1 && s[l] == s[r]) { l--; r++; } return s.substr(l+1,r-l-1); } string longestPalindromeSimple(string s) { intn = s.length(); if(n == 0) return ""; string longest = s.substr(0, 1); // a single char itself is a palindrome for(int i = 0; i < n-1; i++) { string p1 = expandAroundCenter(s, i, i); if (p1.length() > longest.length()) longest = p1; string p2 = expandAroundCenter(s, i, i+1); if (p2.length() > longest.length()) longest = p2; } return longest;