求字符串的最长重复子串,子串可以相交

来源:互联网 发布:使命召唤10 知乎 编辑:程序博客网 时间:2024/05/17 04:21

给定一个字符串,输出最长的重复子串

举例:ask not what your country can do for you,but what youcan do for youcountry

最长的重复子串:can do for you

思路:使用后缀数组解决

分析:

1、由于要求最长公共子序列,则需要找到字符串的所有子串,即通过产生字符串的后缀数组实现。

2、由于要求最长的重复子串,则需要对所有子串进行排序,这样可以把相同的字符串排在一起

3、比较相邻字符串,找出两个子串中,相同的字符的个数。

注意,对于一个子串,一个与其重复最多的字符串肯定是紧挨着自己的两个字符串。

步骤:

      1、对待处理的字符串产生后缀数组

      2、对后缀数组排序

      3、依次检测相邻两个后缀的公共长度

      4、取出最大公共长度的前缀


这里的子串是可以相交的,比如ababa,返回的最长重复子串的长度为3

/* * 使用后缀数组,具体思路参见http://blog.csdn.net/iamskying/article/details/4759485 不过 * 1.这个思路在生成后缀数组时,用“暴力”生成:先取最后1个元素,然后取最后2个元素、最后3个元素... * 据说可以通过倍增算法和DC3算法,不过没研究过... 2.下面这个结论我不明白,后缀数组的原理还没研究过--> * “将所有后缀数组按字典顺序排序后,两个相邻位置的后缀数组比较,取其最长公共前缀,即为所求字符串s的最长可重叠重复子串” */public void findMaxPrefixCross(String str) {String[] suffixArray = generateSuffixArray(str);// string sortList<String> list = (List<String>) Arrays.asList(suffixArray);Collections.sort(list);// 两个相邻位置的后缀数组比较,取其最长公共前缀// int startIndex=0;//只有第一个字符相同时,才有“公共前缀”int prefixLen = -1;int index = -1;for (int i = 0, len = suffixArray.length; i < len - 1; i++) {char[] str1 = suffixArray[i].toCharArray();char[] str2 = suffixArray[i + 1].toCharArray();int k1 = 0, k2 = 0;int len1 = str1.length, len2 = str2.length;int count = 0;if (str1[0] == str2[0]) {// 只有第一个字符相同时,才有“公共前缀”while (k1 < len1 && k2 < len2 && str1[k1] == str2[k2]) {k1++;k2++;count++;}if (count > prefixLen) {prefixLen = count;index = i;}}}if (index != -1) {String str3 = suffixArray[index];System.out.println("one of the max repeat SubString is "+ str3.substring(0, prefixLen));System.out.println("length=" + prefixLen);} else {System.out.println("no duplicate char ");}}public String[] generateSuffixArray(String str) {int len = str.length();String[] suffixArray = new String[len];for (int i = 0; i < len; i++) {int endIndex = len;int beginIndex = len - 1 - i;suffixArray[i] = str.substring(beginIndex, endIndex);}return suffixArray;}


0 0