【题目链接】
【题目考点】
1. 字符串
2. 环形数组遍历
环形数组元素个数为n,下标为0~n-1,在环形数组中下标i取下一个位置的方法:i = (i + 1) % n
环形数组中下标i后第j个位置的下标为:(i + j) % n
3. 环形数组转一维数组
一个环形数组有n个元素。如想遍历该环形数组,同时取一段子数组做某种运算,而该子数组的长度小于等于2n,那么就可以将该环形数组变为一个长为2n的一维数组,将环形数组中的元素在一维数组上排列两遍,而后在该一维数组上做遍历。
例:在环形数组上找最大子段和
假设环形数组为:4 -4 2 -3 5 -3
转为一维数组:4 -4 2 -3 5 -3 4 -4 2 -3 5 -3
其最大子段和为5-3+4=6
【解题思路】
解法1:在环形数组上遍历
输入两个字符串到s1和s2,其长度分别为l1、l2。i1与i2分别为s1与s2的下标,i1从0遍历到l1-1, i2从0遍历到l2-1。对于每对i1, i2,看s1从i1开始,与s2从i2开始,相同的子串最长可以是多长。在这一过程中,需要使用在环形数组中取下一个位置的写法,即形如i = (i + 1) % n
的写法。对每次取到的子串长度取最大值,即为结果。
解法2:环形数组转为一维数组
将两个环形字符串转为一维字符串(方法见题目考点3),而后就是两个一般字符串找最长公共子串的问题了,做法与解法1相似,遍历时下标直接加1即可。
【题解代码】
解法1:在环形数组上遍历
#include<bits/stdc++.h>
using namespace std;
#define N 260
int main()
{
char s1[N], s2[N];
int i1 = 0, i2 = 0, l1, l2, mxLen = 0;//i1, i2分别是s1, s2的下标 mxLen:最大公共子串长度
cin >> s1 >> s2;
l1 = strlen(s1);
l2 = strlen(s2);
for(int i1 = 0; i1 < l1; ++i1)
for(int i2 = 0; i2 < l2; ++i2)
{
int j = 0;//j为公共子串长度,最长也就是l1和l2的较小值
while(j < l1 && j < l2)
{
if(s1[(i1+j)%l1] == s2[(i2+j)%l2])//在环形数组s1中i1后第j个元素下标为(i1+j)%l1,s2中i2后第j个元素下标为(i2+j)%l2
j++;
else
break;
}
mxLen = max(mxLen, j);
}
cout << mxLen;
return 0;
}
解法2:环形数组转为一维数组
#include<bits/stdc++.h>
using namespace std;
#define N 260
void doubleArr(char s[])//将s变为原来的s重复2遍 如将abc变为abcabc
{
int len = strlen(s);
for(int i = 0; i <= len; ++i)
s[i+len] = s[i];
}
int main()
{
char s1[N], s2[N];
int i1 = 0, i2 = 0, l1, l2, mxLen = 0;//i1, i2分别是s1, s2的下标 mxLen:最大公共子串长度
cin >> s1 >> s2;
l1 = strlen(s1);
l2 = strlen(s2);
doubleArr(s1);//将字符串变为原字符串重复2遍,即为用一维数组表示环形数组
doubleArr(s2);
for(int i1 = 0; i1 < l1; ++i1)
for(int i2 = 0; i2 < l2; ++i2)
{
int j = 0;//j为公共子串长度,最长也就是l1和l2的较小值
while(j < l1 && j < l2)
{
if(s1[i1+j] == s2[i2+j])
j++;
else
break;
}
mxLen = max(mxLen, j);
}
cout << mxLen;
return 0;
}