寻找字符串中最长重复子串----求特征向量N法

题目

编写算法,对给定字符串str,返回其最长重复子串及其下标位置。

eg:str=“abcdacdac”,则子串“cdac”是str的最长重复子串,下标为2

题目分析

1. 第一步:遍历字符串得到所有子串的特征向量N
2. 第二步:找到所有子串的最大特征向量NN_max
3. 第三步:返回最长重复字符串的下标

实现细节

  • 遍历字符串中的每个字符,根据前缀子串和左子串匹配的方式,得到每个字符对应的特征值N;
    在这里插入图片描述

  • 将a中得到的所有字符串对应的特征值比较,将最大值保存在数组N_Store中;

  • 去掉字符串第一个字符,再次重复a,b。并立即比较N_Store数组中存放的几个最大特征向量的大小,将大的一个保存在变量NN_max中,并用index_NN_max记录此时对应元素在N_Store数组中的下标;

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 如果删除后剩余的字符串长度比NN_max小则不再进行删除操作,否则继续删除,即重复c操作;
  • 最后得到index_NN_max是最长重复子串的起始位置,NN_max是最长重复子串的长度;

函数及其功能

getmax_N(string P,int* N):求特征向量数组中最大的特征值
Next(string P)

  1. 求出字符串P的每个字符对应的特征向量;
  2. 求出1中所有特征向量的最大值,将该值存入数组N_Store中;
  3. 如果已经进行了多次该操作,那么比较这几次操作每次所得最大特征向量的最大值,得到目前最长重复子串的长度和起始下标,之后每递归一次,就更新一次最长子串长度和对应起始下标,直到找到目标值就不再更新;

main():返回得到的最长重复子串和其对应起始位置;

使用参数及具体函数

#define SIZE 1000    
int N_Store[SIZE] = {0};    // 用来存放每次删除操作后,得到的字符串特征向量的最大值
int NN_max = N_Store[0];    // 用来存放所有最大值中的最大值,即最长重复子串长度
static int countn = 0;    // 用来存放N_Store数组的有效值长度
int index_NN_max = 0;    // 存放最长重复子串的起始下标

getmax_N(string P,int* N) :

/*
求特征向量数组中最大的特征值
P:特征向量数组对应的字符串
N:特征向量数组
maxN:本次特征向量数组中的最大值
*/
int getmax_N(string P,int* N) {    
    int maxN = N[0];
    int n = 0;
    while (n<P.length())    // 遍历数组N(因为N存放的是本次字符串P的特征值向量数组,所以直接用P.length),取最大值
    {
        maxN = max(N[n++], maxN);
    }
    return maxN;
}

Next(string P)

/*
特征向量更新函数
P:要判断的字符串;
m:字符串长度;
N[]:字符串对应的特征向量数组;
完成工作:
1. 求出字符串P的每个字符对应的特征向量
2. 求出1中所有特征向量的最大值,将该值存入数组N_Store中
3. 如果已经进行了多次该操作,那么比较这几次操作每次所得最大特征向量的最大值
*/
int* Next(string P) {
    int m = P.length();    
    assert(m > 0);
    int* N = new int[m];
    assert(N != 0);
    N[0] = 0;    // 设定特征向量第一个值为0
    for (int i = 1; i < m; ++i) {    // 遍历字符串
        int k = N[i - 1];    // 找到i位置上一个的特征值N[i-1]
        while (k > 0 && P[k] != P[i])    // 画图表示
        {
            k = N[k - 1];
        }
        N[i] = (P[i] == P[k]) ? k + 1 : 0;    // 图上表示
    }
    int maxN = getmax_N(P,N); // 调用函数,求本次的P字符串的特征向量最大值N
    cout << "特征向量数组中最大的特征值是:" << endl;
    cout << maxN << endl;
    N_Store[countn] = maxN;    // 将本次P字符串的特征向量最大值放入N_Store数组中
    int flag_maxN = NN_max;
    if (countn >= 1) {    
        NN_max = max(NN_max, N_Store[countn-1]);    // 求出当前N_Store数组中最大的特征向量(最大的最大)
        if (NN_max != flag_maxN) {    // 当最大特征值更新之后,对应的下标也更新
            index_NN_max = countn - 1;    // 记录最长重复子串的起始下标
        }
    }
    countn++;    // countn+1,让N_Store数组后移
    if (P.length() > NN_max&& P.length() > 1) {    // 删除字符串中第一个元素的判断标准,如果当前字符串的长度已经比当前所得最大特征向量值小的话,就无需再删除
        for (int t = 0; t < m - 1; t++) {
            P[t] = P[t + 1];    // 这时候最后一个元素是没有删除的,担心越界,所以设置的m-1
        }
        if (!P.empty()) {
            P.pop_back(); // 将字符串最后一个位置的元素删除
        }
        Next(P);    // 递归操作,将删除了首个元素之后的字符串,再次进行特征值的计算,求所有特征值最大值等工作
    }

    return N;
}

main()

int main() {
    static string str;
    str = "abcdacdac";
    string str_Store = str;    // 该str_Store字符串用于储存最开始未进行删除操作的str字符串
    Next(str);    // 进行求字符串及其子串特征向量的工作,得到的N_Store数组包括了特征向量数组中最大的特征向量,以及最长重复子串的起始下标index_NN_max和长度NN_max
    printf("删除%d个字符之后,得到的最大重复子串长度为:%d\n", index_NN_max, NN_max);
    for (int out_max = index_NN_max; out_max < index_NN_max + NN_max; out_max++) {
        cout << str_Store[out_max] << "";
    }
}

程序运行结果

在这里插入图片描述

补充(特征向量N的代码解释)

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值