[算法]寻找一个字符串中的最长重复子串(后缀数组)

寻找一个字符串中的最长重复子串(后缀数组)

因为工作场景,需要对字符串中重复的子串进行删除操作,那么最重要的过程就是找到最长重复字串,网上有很多暴力方法,我觉得没什么意思,同事也说可以使用正则,然而我不会,所以还是用拿手的java代码解决吧。(本文参考:https://blog.csdn.net/u012114090/article/details/81669021)

后缀数组其实可以看寻找一个字符串中的最长重复子串(后缀数组)作一个由字符串s倒数i个字符组成的子串的集合,其中0<i<s.length(),例如 字符串strstr的后缀数组为:
{r,tr,str,rstr,trstr,strstr}
得到这个集合之后,我们可以发现,最长重复子串其实变成了求该集合中任意两个元素的最长公共前缀的问题。因为在这个集合中,原字符串中的每个字符都会出现在集合中元素的首位,而如果有子串重复出现,那么该子串肯定会出现在某两个或者多个元素的公共前缀上。
接下来问题就变成了如何去寻找最长公共前缀,除了暴力搜素之外,我们可以考虑先对该集合中的元素按照字典序进行排序,然后依次比较相邻的元素,找出其中的最长公共前缀即可。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Description TODO
 * @Author zhangzhishun
 * @Date 2020/8/12-12:31
 */
public class Main {

    public static void main(String[] args) {
        String strTestA = "aabbccedbbccea";
        System.out.println(getLongestCommonSubstr(strTestA));
    }

    public static String getLongestCommonSubstr(String str) {
        if (str == null || str.length() == 0) {
            return "";
        }
        // 存放子串
        List<String> substrLst = new ArrayList<>();
        for (int i = 0; i < str.length(); i++) {
            substrLst.add(str.substring(i));
        }
        // 按着字典序升序排序 归并排序时间复杂度:O(nlogn)
        Collections.sort(substrLst);
        String result = "";
        for (int i = 0; i < substrLst.size() - 1; i++) {
            // 比较相邻的元素,找出其中的最长公共前缀
            if (getLongestCommonPrefix(substrLst.get(i), substrLst.get(i + 1)).length() > result.length()) {
                result = getLongestCommonPrefix(substrLst.get(i), substrLst.get(i + 1));
            }
        }
        return result;
    }

    /**
     * 找出两个字符串的最长公共前缀
     */
    public static String getLongestCommonPrefix(String str1, String str2) {
        if (str1 == null || str2 == null || str1.length() == 0 || str2.length() == 0) {
            return "";
        }
        int i = 0;
        while (i < Math.min(str1.length(), str2.length())) {
            if (str1.charAt(i) != str2.charAt(i)) {
                break;
            }
            i++;
        }
        return str1.substring(0, i);
    }
}

分析时间复杂度:

  1. 生成后缀数组 O(N)
  2. 归并排序 O(nlogn)
  3. 依次检测相邻的两个字符串 O(N * N)

总的时间复杂度是 O(N^2*logN)

代码不长,如有疑问互相交流学习!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯糖不加咖啡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值