#P3557. 第1题-有趣的名字
-
1000ms
Tried: 48
Accepted: 19
Difficulty: 5
所属公司 :
阿里
时间 :2025年9月4日-阿里淘天
-
算法标签>模拟
第1题-有趣的名字
思路
-
核心:用位掩码检测同一字母是否同时出现大小写。
-
扫描字符串:
-
若首字符不是大写,或末字符不是小写,则不喜欢。
-
用两个 26 位掩码 lowerMask、upperMask:
- 遇到小写字母 c,令 idx=c−′a′。若 upperMask 的第 idx 位已置位,则冲突;否则置 lowerMask 的该位。
- 遇到大写字母同理,检查 lowerMask。
-
-
统计所有满足条件的名字数。
正确性说明
- 每个字母对应唯一位,遍历一次即可发现是否存在同一字母的大小写同时出现;首尾条件直接判定,故算法与定义严格一致。
复杂度
- 时间:O(∑mi)
- 空间:O(1)
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
if (!(cin >> n)) return 0;
long long ans = 0;
for (int i = 0; i < n; ++i) {
int m;
string s;
cin >> m;
cin >> s; // 输入保证只含字母,长度为 m
// 条件1:首字母必须是大写
if (s.empty() || !(s[0] >= 'A' && s[0] <= 'Z')) continue;
// 条件2:尾字母必须是小写
if (!(s.back() >= 'a' && s.back() <= 'z')) continue;
int lowerMask = 0, upperMask = 0;
bool ok = true;
for (char ch : s) {
if (ch >= 'a' && ch <= 'z') {
int idx = ch - 'a';
if (upperMask & (1 << idx)) { // 同一字母的大写已出现,冲突
ok = false; break;
}
lowerMask |= (1 << idx);
} else if (ch >= 'A' && ch <= 'Z') {
int idx = ch - 'A';
if (lowerMask & (1 << idx)) { // 同一字母的小写已出现,冲突
ok = false; break;
}
upperMask |= (1 << idx);
} else {
ok = false; break; // 保险:非字母直接不符合(按题意不会发生)
}
}
if (ok) ++ans;
}
cout << ans << '\n';
return 0;
}
Python
import sys
def liked(s: str) -> bool:
# 条件1:首字母大写
if not s or not ('A' <= s[0] <= 'Z'):
return False
# 条件2:尾字母小写
if not ('a' <= s[-1] <= 'z'):
return False
lower_mask = 0
upper_mask = 0
for ch in s:
if 'a' <= ch <= 'z':
idx = ord(ch) - ord('a')
if (upper_mask >> idx) & 1: # 冲突:同字母大写已出现
return False
lower_mask |= (1 << idx)
elif 'A' <= ch <= 'Z':
idx = ord(ch) - ord('A')
if (lower_mask >> idx) & 1: # 冲突:同字母小写已出现
return False
upper_mask |= (1 << idx)
else:
return False # 按题意不会发生
return True
def main():
data = sys.stdin.read().strip().splitlines()
it = iter(data)
n = int(next(it))
ans = 0
for _ in range(n):
_m = int(next(it)) # 读取长度但不强制使用
s = next(it).strip()
if liked(s):
ans += 1
print(ans)
if __name__ == "__main__":
main()
Java
import java.io.*;
import java.util.*;
public class Main {
// 判断是否喜欢的名字
static boolean liked(String s) {
// 条件1:首字母大写
if (s.length() == 0 || !(s.charAt(0) >= 'A' && s.charAt(0) <= 'Z')) return false;
// 条件2:尾字母小写
char last = s.charAt(s.length() - 1);
if (!(last >= 'a' && last <= 'z')) return false;
int lowerMask = 0, upperMask = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch >= 'a' && ch <= 'z') {
int idx = ch - 'a';
if ((upperMask & (1 << idx)) != 0) return false; // 冲突
lowerMask |= (1 << idx);
} else if (ch >= 'A' && ch <= 'Z') {
int idx = ch - 'A';
if ((lowerMask & (1 << idx)) != 0) return false; // 冲突
upperMask |= (1 << idx);
} else {
return false; // 按题意不会发生
}
}
return true;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
int n = Integer.parseInt(line.trim());
long ans = 0;
for (int i = 0; i < n; i++) {
// 读取 m_i
String ms = br.readLine();
while (ms != null && ms.length() == 0) ms = br.readLine();
int m = Integer.parseInt(ms.trim()); // 未使用,仅对齐输入
// 读取 s_i
String s = br.readLine();
while (s != null && s.length() == 0) s = br.readLine();
if (liked(s)) ans++;
}
System.out.println(ans);
}
}
题目内容
Tk 拿到一个包含 n 个名字的名单。第 i 个名字为一个长度为 mi 的字符串 si ,仅由大小写英文字母组成。若一个名字满足以下全部条件,则称其为 Tk 喜欢的名字:
-
名字以大写字母开头(即首字符属于 A ~ Z );
-
名字以小写字母结尾(即末字符属于 a ~ z );
-
对任意一对相同字母的大小写(例如“aA"、"fF"、"rR"),在整个名字中至多出现其中一种形式,也可以两者均不出现。换言之,不允许同时出现某个字母的小写与大写。
请你计算名单中有多少个名字是 Tk 喜欢的。
输入描述
第一行输入一个整数 n(1≤n≤104) ,表示名字的数量。 此后 n×2 行:
第 i×2−1 行输入一个整数 mi(1≦mi≦2×105) ,表示第 i 个名字的长度 ;
第 i×2 行输入一个仅由大小写字母组成、长度为 mi 的字符串 si 。
保证 ∑i=1nmi≦2×105,即单个名单中所有名字长度之和不超过 2×105 。
输出描述
输出一个整数,表示 Tk 喜欢的名字数量
样例1
输入
6
3
Abc
3
Ada
3
XyZ
2
Ff
3
Qwe
4
Bcdz
输出
3
样例2
输入
5
3
Aaa
3
Bob
3
Cat
3
dog
8
Edgecase
输出
1
说明