Count a Character
你会得到一个字符串 s 和一个字母 c。返回 c 在 s 中出现的次数。匹配区分大小写:B 和 b 是不同的字符。
函数
- sstring
- 要搜索的英文字母字符串
- cstring
- 要计数的那个字母
- 返回值integer
- s 中有多少个字符等于 c
约束条件
1 ≤ s.length ≤ 5 × 104s只包含英文字母(a到z,A到Z)。c正好是一个英文字母。
示例
- 输入
- s = "Mississippi"c = "s"
- 输出
- 4
- 解释
Mississippi在索引 2、3、5 和 6 处有s,所以答案是 4。
- 输入
- s = "Banana"c = "b"
- 输出
- 0
- 解释
Banana以大写字母B开头,而你要查找的是小写字母b。没有匹配项,所以答案是 0。
进阶
如果 c 可以是由多个字母组成的单词,比如 ss,会怎样?重叠的匹配也算吗?你的循环要如何调整?
提示
逐个打开提示,每个都会多透露一点。
要知道
c出现了多少次,你需要查看s中的哪些字符?将
s中的每个字符与c进行比较,完全按照它们原本的样子比较。这里大写字母和小写字母是不同的字符。设置一个初始值为 0 的计数器。遍历字符串一次,每当当前字符等于
c时,就加 1。
题解
s 中的任何字符都可能是 c,所以你要逐个检查并统计匹配项。注意大小写:大写字母是不同的字符。
删除每个 c 并比较长度
思路
创建 s 的副本,并移除其中的所有 c。每移除一个字符,副本就会短一个字符,因此长度之差就是数量。对于 Mississippi,副本是 Miiippi:11 减去 7 等于 4。
时间复杂度是 O(n),但副本会额外占用 O(n) 的内存,而计数器不需要这些内存。
算法
- 复制
s,去掉其中所有等于c的字符。 - 计算
s的长度和副本的长度。 - 返回
s的长度减去副本的长度。
def countChar(s, c):
# Every c that disappears makes the string one character shorter.
without = s.replace(c, "")
return len(s) - len(without)带计数器的一次遍历
思路
读取时直接计数,而不是创建副本。计数器从 0 开始,每遇到一个等于 c 的字符就加 1。普通的相等比较可以避免大写字母匹配小写字母。
每个字符只比较一次,并且只存储计数器:时间复杂度为 O(n),空间复杂度为 O(1)。没有比 O(n) 时间复杂度更优的答案,因为你跳过的字符可能又是一个 c。
算法
- 从
c中读取目标字母,并将count = 0。 - 逐个遍历
s中的字符。 - 如果字符与目标字母相同,就将
count加 1。 - 返回
count。
def countChar(s, c):
count = 0
for ch in s:
if ch == c:
count += 1
return count
易错点和边界情况
- 忽略大小写。将两边都转换为小写后,
Banana中的b会返回 1;但答案是 0。 - 将字符与字符串进行比较。在 Java、C、C++、C# 和 Go 中,
c是字符串,而s[i]或s.charAt(i)是单个字符。在循环开始前,先取一次c[0](或c.charAt(0))。 - 在 Java 中使用
==比较字符串。String.valueOf(s.charAt(i)) == c比较的是对象标识,结果几乎总是 false。请比较char值。 - 在 C 中的循环条件里调用
strlen(s)。它会在每一步重新扫描字符串,因此处理5 × 10^4个字符大约需要2.5 × 10^9步。
常见问题3
如何统计一个字符在字符串中出现的次数?
用一个从 0 开始的计数器遍历字符串,每当当前字符等于你要查找的字符时,就加 1。这样需要 O(n) 时间和 O(1) 额外内存。若要进行不区分大小写的计数,先将字符串和字母都转换为小写。
我可以在面试中使用内置的计数函数吗?
通常是的,只要你能说明它的成本。Python 的 str.count 和类似函数仍然会读取整个字符串,所以它们的复杂度是 O(n)。如果面试官要求你写循环,要做好准备。
怎样一次性统计所有字符?
遍历一遍,并在哈希映射中或数组中为 52 个英文字母各自计数。遍历完成后,只需一次查找就能得到任意字母的计数。如果要查询同一字符串中的多个字母,可以使用这种方法。
相似题目
运用相同思路的题目。做两三道,才能真正掌握一种模式。
def countChar(s, c):
# 在这里编写代码测试 #1
测试 #2
参数
s = "Mississippi" c = "s"
预期输出
4