032 · Jewels and Stones

algorithm
Published

June 8, 2026

My First Thoughts

这道题我看看哈,两个字符串 jewelsstones

实际就是一个单层问题:stones 里有多少个字符出现在 jewels 中,对吧?并且题目说区分大小写,所以 "a""A" 要当成两个不同字符。

最直接的写法就是准备一个计数器 total,然后遍历 stones 里的每个字符。如果这个字符在 jewels 里,就把 total 加一:

def jewelsstones(jewels, stones):
    total = 0

    for char in stones:
        if char in jewels:
            total += 1

    return total

这个思路是对的,而且在这道题里已经够用。因为题目只是在问“有多少块石头也是宝石”,所以每块石头看一次,能数就数,不能数就跳过。

这里还可以延申一下:如果题目变成“不考虑大小写”,那就可以把两边都转成小写再比较。这个方向也合理,只是 Python 里调用 lower 要带括号:

def jewelsstones_ignore_case(jewels, stones):
    total = 0
    jewels_lower = jewels.lower()

    for char in stones:
        if char.lower() in jewels_lower:
            total += 1

    return total

不过这是延申版本,不是原题版本。原题明确区分大小写,所以最终解法不能把字符统一转小写。


Why That Is Not Enough

直接写:

if char in jewels:

逻辑上没有问题。这道题的约束也很小,jewelsstones 最长都是 50,所以直接查字符串也能通过。

真正可以改进的地方是:这句代码背后的操作是“判断一个字符是否属于宝石类型”。如果 jewels 是字符串,那么每次 char in jewels 都可能要在字符串里从头找一遍。

比如:

jewels = "abcdef"
char = "f"

为了确认 "f" 在不在里面,可能要看过 "a""b""c""d""e",最后才找到 "f"

但这道题里,jewels 更像一个集合:它表示“哪些字符是宝石”。当我们反复问:

这个字符是不是宝石?

set 更自然。set 的目的就是快速回答“某个东西在不在这一组东西里”。所以最终代码可以在你的直接循环基础上只改一处:先把 jewels 转成 set,后面查 jewel_set


Final Idea

关键思路是:

先把所有宝石类型放进 set,再遍历 stones 统计哪些石头出现在这个集合里。

从你的第一版开始:

if char in jewels:

把右边的 jewels 换成一个提前准备好的集合:

jewel_set = set(jewels)

if char in jewel_set:

set(jewels) 会把字符串拆成一个个字符,放进集合里。比如:

set("aA")

得到的意思就是:

{"a", "A"}

然后遍历 stones

看到 "a" -> 在集合里,total += 1
看到 "A" -> 在集合里,total += 1
看到 "b" -> 不在集合里,跳过

这样代码仍然是很直观的计数逻辑,只是 membership check 从“在字符串里找”变成了“在集合里查”。


Why It Works

jewel_set 包含了所有宝石类型。因为题目说 jewels 中的字符互不相同,所以把它转成 set 不会丢掉任何有效信息。

接下来,stones 中每个字符都代表一块石头。对每块石头来说,只有两种情况:

  • 它在 jewel_set 里,说明这块石头是宝石,计数加一
  • 它不在 jewel_set 里,说明这块石头不是宝石,计数不变

遍历完所有 stones 后,total 就正好等于宝石石头的数量。

大小写也会自然保持正确。因为 Python 的字符串字符本来就区分大小写,"z""Z" 是不同字符。只要我们不调用 lower()upper(),示例 2 里的 jewels = "z"stones = "ZZ" 就会返回 0


Code

def numJewelsInStones(jewels, stones):
    jewel_set = set(jewels)
    total = 0

    for char in stones:
        if char in jewel_set:
            total += 1

    return total

也可以写成更短的版本:

def numJewelsInStones(jewels, stones):
    jewel_set = set(jewels)
    return sum(char in jewel_set for char in stones)

不过初学时第一版更清楚:total 表示当前已经数到的宝石数量,每遇到一块宝石就加一。


Complexity

Time \(O(j + s)\) - jjewels 的长度,sstones 的长度;先建集合,再遍历所有石头
Space \(O(j)\) - jewel_set 里最多保存 jewels 中的所有字符

Takeaway

如果题目反复问“某个东西在不在这一组东西里”,set 通常是很自然的工具。直接用字符串查找在这道题里也能过,但把 jewels 转成 set 后,代码的含义更贴近题目:jewel_set 就是所有宝石类型的集合,char in jewel_set 就是在问“这块石头是不是宝石”。


Quiz