动态规划与最长重复子串 LRS and Dynamic Programming

最长重复子串问题

假设我们有一个字符串,要如何求出在这个字符串里最长的重复子串呢?比如给出字符串abcdeefabcd,显然这个字符串的重复子串有很多,比如abababc 等等,那么通过观察,我们可以知道这个字符串的最长重复子串(Longest Repeated Substring)为abcd

如果要用编程的方法来找出这个最长重复子串,应该怎么做呢?

暴力遍历

非常正常的想法是遍历,利用三重循环,每一次比较两个相等长度的子字符串是否相等,将记录下的最大长度与该子字符串进行比较,如果更长,则更新答案。简单的代码如下:

#include<iostream>
#include<string.h>
using namespace std;
string naiveLRS(string s)
{
   
    int maxm=0; //重复子字符串的最大长度
    string ans = "";
	for(int i=0;i<s.length();i++)
	{
   
		for(int j=i;j<s.length();j++)
		{
   
			string x=s.substr(i,j-i+1);  //一个子字符串
			for(int k=i+1;k<s.length();k++) //从i+1开始,因为如果从i开始,两字符串的起点相同,得到的答案必定为原字符串s
			{
   
				string y=s.substr(k,j-i+1); //另一个与x不相等的子字符串
				if(x == y && x.length() > maxm) //如果这两个字符串相等,并且长度比之前记录的maxm更大,则更新答案
                {
   
                    maxm = x.length();
                    ans = x;
                }
			}
		}
	}
	return ans;
}

int main()
{
   
	string s,ans;
	cout << "Enter the input string:-\n";
	cin >> s;   //输入字符串
    ans = naiveLRS(s);
	cout << "The longest repeating substring is:- " << ans << '\n'; //输出答案
	return 0;
}

显然,这种方法的时间复杂度是 O ( n 3 ) O(n^3) O(n3),空间复杂度为 O ( 1 ) O(1) O(1)。值得一提的是,在第三层循环中,是不需要考虑如果长度 j − i + 1 j-i+1 ji+1超出字符串长度的情况,因为在substr()函数中,如果给出的长度超出了字符串原本的长度,会自动截取到字符串的结尾。

动态规划

显然,前面提到的暴力解法涉及到了非常多的重复计算。而动态规划的思想,实际上就是利用“记忆”下来的数据,避免这些重复计算。这些“记忆”下来的数据,大概可以理解成“历史记录”。我们一般会用一个数组dp来存放这些“历史记录”。问题是,这个数组的意义是什么,里面的值应该怎样更新呢?

LRS问题中dp数组的意义

首先呢,我们需要明确这个dp数组的意义。在我们提到的最长重复子串问题中,dp[i][j]存储的是以第i和第j个字符结尾的重复子字符串的长度。这样表述还是有点抽象,以一个具体的字符串为例子,如banana。我们会将dp数组初始化如下:

b a n a n a
i \ j 0 1 2 3 4 5
b 0 0 0 0 0 0 0
a 1 0 0 0 0 0 0
n 2 0 0 0 0 0 0
a 3 0 0 0 0 0 0
n 4 0 0 0 0 0 0
a 5 0 0 0 0 0 0

事实上就是一个n*n的矩阵(n为字符串的长度),初始化为0。那么我们从i开始遍历。起初 i = 0 i=0 i=0,那么开始遍历 j j j,为了避免得到两个完全重合的子字符串, j j j的初始值为 i + 1 i+1 i+1,也就是1,随后我们比较 s [ i ] s[i]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值