题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例 1),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例 2)。 输入格式 共 2 行。 第 1 行为一个字符串,其中只含字母,表示给定单词; 第 2 行为一个字符串,其中只可能包含字母和空格,表示给定的文章。 输出格式 一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从 0 开始);如果单词在文章中没有出现,则直接输出一个整数 −1。 注意:空格占一个字母位 以下是我的代码请修改: #include<bits/stdc++.h> using namespace std; string caps(string a) { for(int i=0;i<a.size();i++) { if(a[i]>='A'&&a[i]<='Z') a[i]+=32; } return a; } int main() { string stra,tem; int fir=0; cin>>stra; stra=caps(stra); vector<string> strb; for(int i=0;cin>>tem;i++) { strb.push_back(tem); } int num=0; for(int i=0;i<strb.size();i++) { strb[i]=caps(strb[i]); if(strb[i]==stra) { if(num==0) { for(int j=0;j<i;j++) { fir+=strb[j].size()+1; } } num++; } } if(num!=0) { cout<<num<<" "<<fir; } else { cout<<-1; } return 0; }
时间: 2025-07-21 17:53:31 浏览: 3
<think>题目要求:统计给定单词在文章中出现的次数和第一次出现的位置(位置从0开始)。匹配时不区分大小写,但要求完全匹配(即必须是独立单词,且忽略大小写后完全相同)。
原代码存在的问题:
1. 输入文章时,原代码使用`cin>>tem`循环读取,这样会跳过空格,但是题目要求的位置是包括空格在内的(因为空格也占位置)。原代码计算位置的方式是累加前面每个单词的长度再加1(空格),但这样计算的前提是每个单词后面都有一个空格,而最后一个单词后面没有空格。另外,如果文章开头有空格,这种计算方式也会出错。
2. 题目要求的位置是单词首字母在文章中的位置(整个文章字符串中的索引),而原代码没有直接读取整行文章,而是用多个单词拼接,这样无法准确得到位置(因为原文中可能有连续空格,或者开头空格等)。
3. 原代码在计算第一次出现的位置时,是在循环中累加前面单词的长度和空格数。但是,如果文章中有多个连续空格,那么每个单词之间的空格数可能不止一个,而原代码默认每个单词后面只有一个空格,这会导致位置计算错误。
正确思路:
1. 应该读取整行文章,然后按照空格分割单词是不完全正确的,因为题目要求独立单词,所以我们需要识别出单词的边界(空格分隔,但也要考虑开头和结尾)。
2. 我们可以将整个文章字符串保存下来,然后遍历整个字符串,在遍历时提取单词(遇到非字母字符即为分隔符)。同时,我们需要记录每个单词的起始位置。
3. 另一种方法是:将整个文章字符串转换为统一的小写(或大写),同时将给定的单词也转换为同样的大小写。然后,在文章中查找单词,但要注意必须是独立单词。
具体步骤:
方法一(推荐):
- 读取单词,转换为小写(或大写)。
- 读取整行文章,保存为字符串。
- 将整行文章也转换为小写(或大写),但注意保留原始文章用于计算位置(因为位置是原始文章的位置,但匹配不区分大小写,所以我们可以用小写的文章来匹配,但位置对应原始文章)。
- 遍历文章字符串,使用双指针或者状态机的方法来分割单词。同时记录每个单词的起始位置和结束位置。
- 对于每个分割出来的单词(根据非字母字符分割),与目标单词比较,如果相等,则计数,并记录第一次出现的位置(即单词起始位置在原始文章中的索引)。
方法二(使用字符串流):
- 使用字符串流可以按空格分割,但这样会忽略连续空格。而且题目中只包含字母和空格,所以空格是唯一的分隔符。
- 但是,字符串流分割单词时,不能得到每个单词在原始字符串中的位置。因此,我们需要手动记录位置。
这里我们使用方法一,因为需要记录位置,而且题目要求的位置是原始文章中的位置(包括空格)。
步骤:
1. 读取单词,并转换为小写(假设用转换到小写)。
2. 读取整行文章(使用getline)。
3. 创建一个原始文章字符串的副本,并将副本转换为小写(用于比较)。
4. 遍历文章副本(小写版本),同时用一个变量记录当前在原始文章中的位置(索引)。
5. 使用双指针提取单词:当遇到字母时,记录单词的起始位置,然后一直读取直到非字母(即空格)出现,这样就得到一个单词。
6. 比较这个单词(小写)是否与目标单词(小写)相等,如果相等,则:
- 如果是第一次出现,记录这个单词在原始文章中的起始位置(注意:这个起始位置就是单词第一个字母的位置,也就是我们记录的开始索引)。
- 计数增加。
7. 注意:在遍历过程中,遇到非字母(这里只有空格)就直接跳过,并且位置索引继续增加。
但是,题目要求独立单词,即单词必须由非字母字符(这里就是空格)包围。但是文章开头和结尾的单词没有前导或后继空格。因此,我们在提取单词时,实际上就是由空格分隔的连续字母序列。
具体实现:
- 初始化:count=0, firstPos=-1, index=0(当前索引)
- 遍历文章字符串(小写版本)的每个字符:
while (index < len) {
// 跳过空格
while (index < len && 文章副本[index]是空格) index++;
if (index >= len) break;
// 记录单词开始位置
int start = index;
// 读取连续字母
while (index < len && 文章副本[index]是字母) {
index++;
}
// 此时得到一个单词:从start到index-1
string word = 文章副本.substr(start, index - start);
if (word == 目标单词) {
count++;
if (firstPos == -1) { // 第一次出现
firstPos = start; // 注意:这里start是在原始文章中的位置吗?实际上,我们的小写副本和原始文章在位置上是相同的,但原始文章的大小写不影响位置。然而,我们记录的位置是原始文章中的位置,因为我们的索引index是从0开始递增的,而原始文章和小写副本的长度和空格位置一致。
}
}
// 注意:此时index指向空格或者结尾,下一轮循环会跳过空格
}
但是,这里有一个问题:我们使用的是小写副本,而原始文章中的位置和副本的位置是一一对应的(因为只是做了大小写转换,没有改变长度和空格位置)。所以,start就是原始文章中的位置。
然而,题目要求的位置是原始文章中的位置,而原始文章可能包含大写字母,但我们记录的位置索引是相同的,所以没问题。
但是,我们并没有保存原始文章,因为我们使用的小写副本提取单词。那么,我们如何知道原始文章中单词的起始位置?实际上,我们不需要原始文章的内容,只需要位置索引。因为位置索引在原始文章和副本中是一样的。
因此,我们可以这样做:
- 保存原始文章字符串(用于输出位置?实际上不需要,因为位置索引就是原始文章中的索引,我们只是用副本来判断单词内容)。
- 但是,我们记录的位置索引就是原始文章中的索引,因为我们在遍历原始文章时,索引是同步的。
然而,我们并没有遍历原始文章,而是遍历了小写副本。但是,由于小写副本和原始文章的长度和空格位置完全一致,所以索引是通用的。
所以,我们可以只用一个原始文章字符串,然后创建一个副本(小写)用于匹配。在遍历副本时,索引同时适用于原始文章。
步骤:
1. 读取单词,转换为小写。
2. 使用getline读取整行文章(因为第一行用cin>>读取单词后,后面还有换行,所以需要先忽略换行,再读文章)。
3. 创建文章的小写副本。
4. 初始化:count=0, firstPos=-1, index=0。
5. 遍历小写副本的每个字符,用上述方法提取单词并比较。
注意:题目要求的位置是单词首字母在文章中的位置(即单词第一个字母在整篇文章中的索引),而我们的start就是该单词首字母在小写副本中的索引,这个索引和原始文章中的位置相同。
代码实现:
注意:输入单词后,可能后面还有换行,所以读取文章前要忽略换行。但题目中第一行只有单词(没有空格),所以用cin>>读取单词后,换行还在,需要忽略。
修改后的代码:
但是,题目要求:如果单词在文章中没有出现,则输出-1。
另外,原代码中计算位置的方式错误,所以我们要重写。
我们按照上述方法实现。
注意:题目中文章只包含字母和空格。
代码:</think>你的代码思路基本正确,但存在几个关键问题需要修正:
1. **位置计算错误**:原代码通过累加前面单词长度计算位置,但忽略了空格数量和位置分布
2. **输入处理不完整**:使用`cin >> tem`会跳过空格,无法获取完整的位置信息
3. **边界条件处理**:未考虑文章开头/结尾空格和连续空格的情况
以下是修改后的代码:
```cpp
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
// 将字符串转换为小写
string toLower(string str) {
for (char &c : str) {
if (isupper(c)) {
c = tolower(c);
}
}
return str;
}
int main() {
string target, article;
cin >> target;
cin.ignore(); // 清除输入缓冲区中的换行符
getline(cin, article); // 读取整行文章
string lowerTarget = toLower(target);
string lowerArticle = toLower(article);
int count = 0;
int firstPos = -1;
int index = 0;
int n = lowerArticle.size();
while (index < n) {
// 跳过非字母字符(空格)
while (index < n && lowerArticle[index] == ' ') {
index++;
}
if (index >= n) break;
// 记录单词起始位置
int start = index;
// 读取完整单词
while (index < n && lowerArticle[index] != ' ') {
index++;
}
int end = index;
// 提取单词并比较
string word = lowerArticle.substr(start, end - start);
if (word == lowerTarget) {
count++;
if (firstPos == -1) {
firstPos = start; // 记录原始文章中的位置
}
}
}
if (count > 0) {
cout << count << " " << firstPos;
} else {
cout << -1;
}
return 0;
}
```
### 代码解释:
1. **大小写转换**:
- `toLower()`函数将字符串统一转为小写,实现不区分大小写的比较
- 同时处理目标单词和整篇文章
2. **输入处理**:
- 使用`cin.ignore()`清除缓冲区中的换行符
- `getline()`读取整行文章,保留所有空格和原始位置信息
3. **单词提取与比较**:
- 双指针法遍历文章:`start`标记单词起始位置,`index`扫描到单词结束
- 跳过连续空格,精确提取独立单词
- 直接比较提取的单词和目标单词
4. **位置记录**:
- `firstPos`直接记录单词在原始文章中的起始索引
- 符合题目要求的位置从0开始计数
5. **输出处理**:
- 找到单词:输出次数和首次位置
- 未找到:输出-1
### 关键改进点:
- 直接处理完整文章字符串而非分割后的单词
- 精确记录原始位置而非计算累加值
- 正确处理连续空格和边界情况
- 使用标准函数提高可读性(`tolower`替代手动转换)
阅读全文
相关推荐
















