两遍扫描:第一遍统计每个字符的频次,第二遍按原串位置序回扫,取第一个频次为 1 的字符。
OJ: roj
题目 ID: 1130
难度:入门
标签:入门字符串统计cpp
创建: 2026-09-29 20:14
更新: 2026-10-05 02:53
题目描述
给定一个只包含小写字母的字符串(长度小于 100000),找到第一个仅出现一次的字符并输出它;若不存在,输出 no。输入一行字符串,输出一行答案或 no。样例输入 abcabd,输出 c。
思路
两遍扫描:第一遍统计每个小写字母的出现次数,第二遍按原串位置序回扫,第一个频次为 1 的字符即为答案,扫完都没找到则输出 no。第一遍必须扫完整串频次才能定型,否则读到中间时会把后面才重复的字符误判。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 20:15
# update_at: 2026-09-29 20:15
import sys
from collections import Counter
def solve() -> None:
s = sys.stdin.buffer.read().strip()
freq = Counter(s) # s 是 bytes,迭代得到 0..255 的整数,可直接当下标
# 频次表备好后再按原串顺序回扫,第一个 freq==1 的字符就是答案;扫完都没有则输出 no
print(next((chr(c) for c in s if freq[c] == 1), "no"))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 02:53
* update_at: 2026-10-05 02:53
*/
#include <iostream>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
// freq[c] 记录字符 c 的出现次数;字符集仅含小写字母,共 26 个。
int freq[26];
char s[MAXN];
void solve() {
// 读入整行字符串(可能含空格,但题目限定只含小写字母,单词读入即可)。
// 注意:cin >> s 会在空白处停下,需要先吃掉前导空白再读。
int n = 0;
char ch;
while (cin.get(ch)) {
if (ch == '\n' || ch == '\r') break;
if (ch >= 'a' && ch <= 'z') {
s[n++] = ch;
}
}
// 第一遍:统计每个小写字母的频次。
for (int i = 0; i < n; i++) {
freq[s[i] - 'a']++;
}
// 第二遍:按原串位置序回扫,第一个频次为 1 的字符就是答案。
for (int i = 0; i < n; i++) {
if (freq[s[i] - 'a'] == 1) {
cout << s[i] << "\n";
return;
}
}
cout << "no\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}