最长公共重复不重复子串系列问题

最长公共重复不重复子串系列问题

 

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<len; 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<n; 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;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值