求最长重复子串

一、问题描述

给定一个字符串,求出其最长重复子串
例如:abcdabcd ,最长重复子串是 abcd
最长重复子串可以重叠
例如:abcdabcda ,这时最长重复子串是 abcda ,中间的 a 是被重叠的。

二、分析

1、直观的解法

首先检测长度为 n - 1 的字符串情况,如果不存在重复则检测 n - 2, 一直递减下去,直到 1 。
这种方法的时间复杂度是 O(N * N * N),其中包括三部分,长度纬度、根据长度检测的字符串数目、字符串检测。

2、使用后缀数组

后缀数组:例如对于字符串String str="banana"的后缀数组是a[0]="anana",a[1]="nana",a[2]="ana",a[3]="na",a[4]="a",

改进的方法是利用后缀数组:对一个字符串生成相应的后缀数组后,然后再排序,排完序依次检测相邻的两个字符串的开头公共部分。
这样的时间复杂度为:
1)生成后缀数组 O(N)
2)排序 O(NlogN*N) 最后面的 N 是因为字符串比较也是 O(N)
3)依次检测相邻的两个字符串 O(N * N)
总的时间复杂度是 O(N^2*logN)

三、java实现

分为三步:

第一步:初始化后缀数组

第二步:对后缀数组进行按字典排序

第三步:对后缀数组中相邻元素进行比较,求最长子串

public class MaxSameString {
    /*
     * 比较两个相邻的字符串
     */
    public int sameLen(String str1,String str2){
        int index=0;
        while(index<str1.length() && index<str2.length()){
            if(str1.charAt(index)==str2.charAt(index)){
                index++;
            }else {
                break;
            }
        }
        return index;
    }
    /*
     * 使用快速排序,对字符串按照字典顺序排列
     */
    public void quickSort(String[] after,int start,int end){
        int low=start;
        int high=end;
        String pkey=after[low];
        while(low<high){
            while(low<high && after[high].compareTo(pkey)>0) high--;
            after[low]=after[high];
            while(low<high && after[low].compareTo(pkey)<0) low++;
            after[high]=after[low];
        }
        after[low]=pkey;
        if(start<end){
            quickSort(after, low+1, end);
            quickSort(after, start, low-1);
        }
    }
/**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MaxSameString mss=new MaxSameString();
        String src="banana";//待处理数组
        String[] after=new String[src.length()-1];//后缀数组
        //第一步:初始化后缀数组
        for(int i=0;i<after.length;++i){
            after[i]=src.substring(i+1);
        }
        //第二步:对后缀数组进行按字典排序
        mss.quickSort(after, 0,after.length-1);
        int maxlen=0;
        int maxi=0;//最长字符串出现在后缀数组中的位置
        //第三步:对后缀数组中相邻元素进行比较,求最长子串
        for(int i=0;i<after.length-1;++i){
            int tmp=mss.sameLen(after[i], after[i+1]);
            if(tmp>maxlen){
                maxlen=tmp;
                maxi=i;
            }
        }
        System.out.println("Max length is "+maxlen);
    }

}

 

转载于:https://www.cnblogs.com/enthusiastic/archive/2012/09/27/2706025.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值