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

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

举例: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 sort
		List<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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值