OpenJudge NOI 1.7 26:字符串最大跨距

本文解析了OpenJudge NOI 1.726题目的解题思路,涉及字符串操作,包括find和rfind函数,以及使用字符数组和string类两种方法寻找字符串s中的最大跨距。通过实例展示了如何构造子串s1和s2,并利用这两个子串查找来计算跨越它们的最大距离。
摘要由CSDN通过智能技术生成

【题目链接】

OpenJudge NOI 1.7 26:字符串最大跨距

【题目考点】

1. 字符串
2. string类

string s, s1;

  • s.find(s1):查找s1在s中第一次出现的位置(从左至右查找),如不存在,返回string::npos
  • s.rfind(s1):查找s1在s最后一次出现的位置(从右至左查找),如不存在,返回string::npos
  • s.substr(pos, len): 从下标pos起截取长度为len 的字符串

【解题思路】

解法1:使用字符数组

先读入整个字符串,遍历字符串,通过逗号将整个字符串拆分为s, s1, s2三个字符串。
读到第一个逗号时,将该数组元素改为’\0’,那么该字符串就是题目中说的字符串s。
继续向后遍历,遍历到的字符向s1做数组填充,读到第二个逗号时停止。s1末尾添加’\0’。
继续向后遍历到’\0’,将遍历到的字符填充到s2。至此完成s,s1,s2三个字符串的构造。
以下类似找子串的方法。

  1. 从前向后遍历s,看有没有一段字符与s1相同。方法为给s1也设一个下标i1,如果看到相同字符,i1增加。如果不同,i1变为0。如果i1已经等于s1的长度,那么说明s中包含s1,跳出循环。此时i指向的是s1在s中最后一个字符的后一个位置,如果s中不存在s1,那么i为s的长度l。最后i的值记为a。
  2. 从后向前遍历s,对s2也从后向前遍历,看s中是否存在s2,方法与上面类似。如果s中包含s2,i指向s2在s中第一个字符的前一个位置,如果s中不包含s2,i的值为-1。最后i的值记为b。
  3. 从s1的后一个字符a到s2的前一个字符b,包括a和b,这段字符的个数即为字符串的跨度。其长度为b-a+1。如果二者重叠,或其中有一个不存在b-a+1一定是负数。
解法2:使用string类

输入s,遍历s,找到两个逗号的下标c1,c2。
s1为从c1+1位置开始,长度为c2-(c1+1)
s2为从c2+1位置开始,到s的末尾
最后修改s,为从第0位置开始,长度为c1。
使用成员函数find()在s中查找子串s1,使用rfind()在s中查找s2。如果二者存在,即可确定s1的最后一个字符和s2第一个字符的位置,而后求出s1到s2的跨度。

【题解代码】

解法1:使用字符数组
#include <bits/stdc++.h>
using namespace std;
int main()
{
    char s[355], s1[15], s2[15];
    cin >> s;//先把整个字符串读入s 
    int l, l1 = 0, l2 = 0, i, i1, i2, a, b;//l,l1,l2:s,s1,s2的长度 i,i1,i2:s,s1,s2的下标 
    for(i = 0; s[i] != ',' ; ++i);
    s[i] = '\0';//去掉第一个逗号后面的字符 
    l = i;//更新s的长度 
    i++;
    while(s[i] != ',')//构造s1 
        s1[l1++] = s[i++];
    s1[l1] = '\0';
    i++;
    while(s[i] != '\0')//构造s2
        s2[l2++] = s[i++];
    s2[l2] = '\0'; 
    i = i1 = 0;
    while(i < l)
    {
        if(s[i] == s1[i1])
        {
            i++;
            i1++;
            if(i1 == l1)
                break;
        }
        else if(i1 > 0)//如果i1大于0,那么把i1指向第0位置,再做比较 
            i1 = 0;
        else//如果i1已经为0 s[i]与s1[i1]还是不同,那么看后面的字符 
            i++;
    }
    a = i;//此时i指向s1最后一个字符在s中的后一个位置。如果s中不存在s1,该值为l 
    i = l - 1;//i与i2都指向字符串最后一个字符 
    i2 = l2 - 1;
    while(i >= 0)
    {
        if(s[i] == s2[i2])
        {
            i--;
            i2--;
            if(i2 < 0)
                break;
        }
        else if(i2 != l2 - 1)
            i2 = l2 - 1;
        else
            i--;
    }
    b = i;//此时i指向s2第0个字符在s中的前一个位置。如果不存在s2,该值为-1 
    //此时,s1和s2间的字符为下标a到b(包括a和b) 
    if(b - a + 1 >= 0)
        cout << b - a + 1;
    else
        cout << -1;
	return 0;
}
解法2:使用string类
#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s, s1, s2;
    int i, c1, c2, a, b;//c1,c2:第一个逗号和第二个逗号的下标  
    cin >> s;//先把整个字符串读入s 
    for(i = 0; s[i] != ','; ++i);
    c1 = i;
    for(i = c1 + 1; s[i] != ','; ++i);
    c2 = i;
    s1 = s.substr(c1 + 1, c2 - c1 - 1);
    s2 = s.substr(c2 + 1);//从c2+1到末尾
    s = s.substr(0, c1);
    a = s.find(s1);//a为s1在s中第一次出现时第一个字符在s中的位置。 
    b = s.rfind(s2);//b为s2在s中最后一次出现时第一个字符在s中的位置。
    if(a == string::npos || b == string::npos)//如果s1或s2不存在 
    {
        cout << -1;
        return 0;
    }
    a = a + s1.length();//a指向s1最后一个字符的后一个位置
    if(b - a >= 0)
        cout << b - a;
    else
        cout << -1;
	return 0;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值