#include <iostream> #include <string> #include <cctype> using namespace std; int main() { string s; getline(cin, s); string s_word; getline(cin, s_word); int sum = 0; int first_pos = -1; // 将待查找的单词转换为小写 string lower_s = s; for (char &c : lower_s) { c = tolower(c); } size_t pos = 0; while ((pos = s_word.find_first_not_of(" \t\n", pos)) != string::npos) { size_t end_pos = s_word.find_first_of(" \t\n", pos); if (end_pos == string::npos) { end_pos = s_word.length(); } string word = s_word.substr(pos, end_pos - pos); // 将当前单词转换为小写 string lower_word = word; for (char &c : lower_word) { c = tolower(c); } if (lower_word == lower_s) { if (sum == 0) { first_pos = pos; } sum++; } pos = end_pos; } if (sum == 0) { cout << -1; } else { cout << sum
时间: 2025-08-20 21:24:49 浏览: 5
<think>好的,用户想要了解C++代码中统计单词出现次数和首次出现位置的逻辑解释或优化方法。我需要先回顾一下之前提供的引用内容,尤其是引用[1]和[4],因为它们提到了统计单词和字符频率的方法。
首先,用户提到的问题是关于统计单词的出现次数和首次位置。根据引用[1],原来的代码使用了二维char数组存储单词,并通过goto循环处理输入,直到遇到“ .”结束。这可能存在效率问题,比如使用goto不够直观,二维数组可能占用较多内存。另外,引用[4]提到使用Map来统计字符次数,类似的方法可以应用到单词统计上。
接下来,我需要分析代码逻辑。原代码可能逐个读取字符,分割单词,并用数组或vector存储单词列表,同时用另一个结构记录次数和首次位置。可能的优化点包括使用更高效的数据结构,比如std::map或std::unordered_map来存储单词及其信息和首次出现的位置,这样查找和更新会更方便。
另外,输入处理部分使用goto可能不够优雅,改用循环结构如while或for会更清晰。例如,使用istringstream来分割单词会更高效,避免手动处理字符,减少错误。
关于统计首次出现的位置,可能需要维护一个记录每个单词首次出现索引的结构。比如,当首次遇到一个单词时,记录当前的位置,之后不再更新。这可以通过在map中存储一个结构体或pair来实现,包含次数和首次位置。
性能方面,如果单词数量大,unordered_map的查找速度更快,因为平均时间复杂度是O(1),而map是O(log n)。但需要权衡是否需要有序遍历。此外,可以考虑预分配内存,减少动态扩容的开销。
用户还可能关心如何处理大小写和标点,比如是否将单词转为小写,是否过滤标点符号。这些细节需要在代码中处理,比如在分割单词前先清理字符串。
最后,测试用例的覆盖也很重要,比如空输入、重复单词、大小写混合等情况,确保代码的鲁棒性。可能还需要优化输入处理,比如使用更标准的终止条件,而不是依赖特定的符号组合。</think>### C++统计单词出现次数及首次位置的代码逻辑解释与优化
#### 基础实现逻辑
1. **输入处理**
- 使用`cin`逐词读取,默认以空格分隔单词,遇到`.`停止输入[^1]
- 示例代码片段:
```cpp
vector<string> words;
string tmp;
while (cin >> tmp && tmp != ".") {
words.push_back(tmp);
}
```
2. **统计次数与位置**
- 通过`unordered_map<string, pair<int, int>>`结构存储:
- `first`:单词首次出现位置
- `second`:出现总次数
```cpp
unordered_map<string, pair<int, int>> wordStats;
for (int i=0; i<words.size(); ++i) {
if (!wordStats.count(words[i])) {
wordStats[words[i]] = {i, 1}; // 记录首次位置
} else {
wordStats[words[i]].second++; // 仅更新次数
}
}
```
#### 优化建议
1. **输入优化**
- 使用`istringstream`处理整行输入,避免逐词读取的潜在问题:
```cpp
string line;
getline(cin, line, '.'); // 读取到'.'为止
istringstream iss(line);
```
2. **数据结构优化**
- 改用`unordered_map`替代原始数组遍历,时间复杂度从$O(n^2)$降为$O(n)$
- 预分配内存减少哈希冲突:
```cpp
wordStats.reserve(words.size()/2);
```
3. **处理边界条件**
- 增加大小写统一处理:
```cpp
transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
```
- 过滤标点符号(正则表达式):
```cpp
tmp = regex_replace(tmp, regex("[^a-zA-Z]"), "");
```
4. **输出优化**
- 保持输入顺序输出时,可改用`vector<tuple>`存储结果:
```cpp
vector<tuple<string, int, int>> output;
for (const auto& w : words) {
if (wordStats[w].second > 0) {
output.emplace_back(w, wordStats[w].first, wordStats[w].second);
wordStats[w].second = 0; // 防止重复输出
}
}
```
#### 完整优化示例
```cpp
#include <iostream>
#include <unordered_map>
#include <vector>
#include <sstream>
#include <algorithm>
#include <regex>
using namespace std;
int main() {
string line;
getline(cin, line, '.'); // 读取到'.'停止
line = regex_replace(line, regex("[^a-zA-Z ]"), ""); // 去除非字母字符
vector<string> words;
istringstream iss(line);
string tmp;
while (iss >> tmp) {
transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
words.push_back(tmp);
}
unordered_map<string, pair<int, int>> wordStats;
wordStats.reserve(words.size()/2);
for (int i=0; i<words.size(); ++i) {
auto& entry = wordStats[words[i]];
if (entry.second == 0) {
entry.first = i;
entry.second = 1;
} else {
entry.second++;
}
}
// 按输入顺序输出
for (const auto& w : words) {
auto& stat = wordStats[w];
if (stat.second != 0) {
cout << w << ": 首次位置=" << stat.first
<< ", 次数=" << stat.second << endl;
stat.second = 0; // 标记已输出
}
}
}
```
#### 性能对比
| 方法 | 时间复杂度 | 空间复杂度 | 特点 |
|--------------|------------|------------|---------------------------|
| 原始数组遍历 | $O(n^2)$ | $O(n)$ | 实现简单,适合小数据量 |
| 哈希表法 | $O(n)$ | $O(n)$ | 大数据量效率提升显著[^4] |
阅读全文