Jewels and Stones
You get two strings of letters. Each letter in jewels names one kind of jewel, and no letter repeats. Each letter in stones is one stone you own. Return how many of your stones are jewels. Letters are case-sensitive: "a" and "A" are different kinds.
Function
- jewelsstring
- the kinds of stones that count as jewels, one letter each
- stonesstring
- the stones you own, one letter each
- Returnsinteger
- the number of stones whose letter appears in jewels
Constraints
1 ≤ jewels.length ≤ 521 ≤ stones.length ≤ 104- Both strings contain only English letters, lowercase and uppercase.
- The letters of
jewelsare all different.
Examples
- Input
- jewels = "rR"stones = "rubyRRr"
- Output
- 4
- Explanation
- The jewel kinds are
randR. InrubyRRrthe stonesr,R,Randrmatch, whileu,bandydo not, so the answer is4.
- Input
- jewels = "z"stones = "ZZZ"
- Output
- 0
- Explanation
- The only jewel kind is lowercase
z. Every stone is an uppercaseZ, a different kind, so none of them counts.
Hints
Open them one at a time. Each one gives away a little more.
For one stone, what question decides whether it counts?
You ask "is this letter a jewel?" once per stone. What structure answers that question in constant time?
Put the letters of
jewelsin a set, then walkstonesand count every letter the set contains. Keep the case as it is.
Solution
For every stone you ask one question: is this letter a jewel? Searching the jewels string for each stone repeats the same scan. Put the jewel letters in a set once, and every stone becomes a single lookup.
Scan the jewels for every stone
Intuition
For each stone, walk through jewels and stop at the first equal letter; a match adds 1 to the count. Stopping there is safe because the jewel letters are all different, so a stone matches at most one of them. In the first example the stone u is compared with r and R and adds nothing.
With j jewel kinds and s stones that is up to j × s comparisons. Since j ≤ 52, 10^4 stones cost about 5 × 10^5 comparisons, which is fast here. The cost grows with the number of kinds, because the same search runs again for every stone.
Algorithm
- Set
countto0. - For each stone, compare it with each letter of
jewels. - On the first equal letter, add
1tocountand move on to the next stone. - Return
count.
def numJewelsInStones(jewels, stones):
count = 0
for stone in stones:
for jewel in jewels:
if stone == jewel:
count += 1
break # the kinds are distinct: no second match is possible
return countPut the jewels in a set
Intuition
The answer to "is this letter a jewel?" never changes for a given letter, so compute it once per kind: build a set from the letters of jewels. A set answers membership in constant time, so each stone costs one lookup instead of a scan.
For the first example the set is {r, R}. Walking rubyRRr, the lookups say yes, no, no, no, yes, yes, yes: four jewels. Building the set takes j steps and the walk takes s, so the total is O(j + s). In a language without a built-in set, an array of flags indexed by character code does the same job.
Algorithm
- Build a set containing every letter of
jewels. - Set
countto0. - For each stone, add
1tocountif the set contains it. - Return
count.
def numJewelsInStones(jewels, stones):
kinds = set(jewels)
count = 0
for stone in stones:
if stone in kinds:
count += 1
return count
Pitfalls and edge cases
- Ignoring case. Lowercasing both strings makes
zmatchZ, and the second example returns3instead of0. - Counting distinct jewel kinds instead of stones.
rubyRRrholds two kinds of jewel but four jewel stones; repeats count. - Building the set inside the stone loop. That costs
jsteps per stone and brings backO(j × s). - Swapping the arguments. The set must hold
jewelsand the loop must walkstones. Reversed,("a", "aaa")returns1instead of3.
Frequently asked questions3
What is the time complexity of Jewels and Stones?
With a set it is O(j + s): j steps to build the set from jewels and one constant-time lookup for each of the s stones. Scanning jewels for every stone is O(j × s).
Why use a hash set for Jewels and Stones?
Every stone asks whether its letter is a jewel. A hash set answers in constant time, while searching the jewels string takes time proportional to its length. You pay once to build the set and save on every stone after that.
Can you solve it without a set?
Yes. The letters are English letters, so an array of 128 flags indexed by character code works as a set with no hashing. Mark each jewel letter, then count the stones whose flag is set.
Similar problems
Problems that use the same ideas. Solving two or three of them is what makes a pattern stick.
def numJewelsInStones(jewels, stones):
# Write code hereTest #1
Test #2
Arguments
jewels = "rR" stones = "rubyRRr"
Expected Output
4