OpenJudge NOI 1.7 30:字符环

【题目链接】

OpenJudge NOI 1.7 30:字符环

【题目考点】

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值