信息学奥赛一本通题目解析:1954:【11NOIP普及组】统计单词数(字符串)

文章讨论了如何使用编程方法实现文本编辑器中查找单词的功能,包括忽略大小写、精确匹配和计算出现次数及首次出现位置。
摘要由CSDN通过智能技术生成

【题目描述】

一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。

现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2)。

【输入】

2 行:

第 1 行为一个字符串,其中只含字母,表示给定单词;

第 2 行为一个字符串,其中只可能包含字母和空格,表示给定的文章。

【输出】

只有一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从0 开始);如果单词在文章中没有出现,则直接输出一个整数-1。

【输入样例】

To
to be or not to be is a question

【输出样例】

2 0

【提示】

【输入输出样例 1 说明】

输出结果表示给定的单词 To 在文章中出现两次,第一次出现的位置为0。

【输入输出样例 2】

输入:

to
Did the Ottoman Empire lose its power at that time

输出:

-1

【输入输出样例 2 说明】

表示给定的单词 to 在文章中没有出现,输出整数-1。

【数据范围】

1 ≤ 单词长度≤ 10。

1 ≤ 文章长度≤ 1,000,000。

【样例分析】

输入样例

To

to be or not to be is a question

分析步骤

  1. 预处理:给定的单词To和文章to be or not to be is a question都被转换为小写,以便进行不区分大小写的匹配。转换后的单词是to,文章变为to be or not to be is a question

  2. 遍历与匹配

    • 文章从头开始遍历,首先找到的单词是to,它与给定的单词to匹配,计数器加1,且这是第一次出现,所以第一次出现的位置记录为0。
    • 继续遍历文章,第二次找到的匹配单词也是to,计数器加1,变为2。不需要更新第一次出现的位置。
    • 文章中其他的单词都不与给定的单词to匹配。
  3. 输出结果:根据遍历和匹配的结果,to在文章中出现了2次,第一次出现的位置是0。因此,输出2 0

输出样例

2 0

直观分析
  • 给定的单词To(不区分大小写)在文章中首次出现在开头位置(位置0),随后再出现一次,共出现两次。
  • 输出2 0表示给定单词在文章中出现了2次,且第一次出现的位置是文章的开头(位置编号从0开始)。

输入输出样例 2 分析

输入

to

Did the Ottoman Empire lose its power at that time

过程
  • 给定单词to在文章Did the Ottoman Empire lose its power at that time中没有出现(注意,这里的“to”不是任何单词的一部分,比如“Ottoman”)。
输出

-1

直观分析
  • 给定单词to在这篇文章中没有独立出现,所以输出-1表示没有找到匹配的单词。

【解题思路】

  1. 预处理:将给定的单词和文章中的所有字母转换为同一种大小写形式,以便于不区分大小写地进行比较。通常,转换为全小写或全大写都是可行的。

  2. 分割文章:将文章按空格分割成单词数组。这一步是必要的,因为题目要求完全匹配单词,而不是文章中的字符串片段。

  3. 匹配与统计:遍历分割后的单词数组,对于每个单词,检查它是否与给定单词完全匹配:

    • 如果匹配,增加计数器的值。
    • 如果是第一次匹配(即计数器从0变为1时),记录下这时的索引位置作为第一次出现的位置。
  4. 输出结果:根据匹配的次数输出结果:

    • 如果计数器大于0,输出匹配次数和第一次出现的位置。
    • 如果计数器为0,表示没有找到匹配的单词,直接输出-1。

【代码实现】

#include <iostream>
#include <string>
#include <cctype> // 用于tolower函数

using namespace std;

// 转换字符串为小写
string toLowerCase(const string& str) {
    string result;
    for (char ch : str) {
        result += tolower(ch);
    }
    return result;
}

// 检查是否为单词的分隔符
bool isSep(char ch) {
    return ch == ' ' || ch == '\t' || ch == '\n';
}

int main() {
    string word, text;
    getline(cin, word);
    getline(cin, text);

    // 转换为小写
    word = toLowerCase(word);
    text = toLowerCase(text);

    int count = 0, firstPosition = -1;
    int len = text.length(), wordLen = word.length();

    for (int i = 0; i <= len - wordLen; ++i) {
        // 找到单词的起始位置
        if ((i == 0 || isSep(text[i-1])) && (i + wordLen == len || isSep(text[i + wordLen]))) {
            if (text.substr(i, wordLen) == word) {
                count++;
                if (firstPosition == -1) {
                    firstPosition = i;
                }
            }
        }
    }

    if (count > 0) {
        cout << count << " " << firstPosition << endl;
    } else {
        cout << -1 << endl;
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值