# Jewels and Stones

This post is part of the Algorithms Problem Solving series.

## Problem description

This is the Jewels and Stones problem. The description looks like this:

You're given strings `J` representing the types of stones that are jewels, and `S` representing the stones you have. Each character in `S` is a type of stone you have. You want to know how many of the stones you have are also jewels.

The letters in `J` are guaranteed distinct, and all characters in `J` and `S` are letters. Letters are case sensitive, so `"a"` is considered a different type of stone from `"A"`.

## Examples

``````# input: J = "aA" | S = "aAAbbbb"
# output: 3

# input: J = "z", S = "ZZ"
# output: 0
``````

## Solution

At first, I tried to understand some corner cases. For example, what should I return if the `J` or the `S` are an empty string?

As my first solution, the brute force solution, I needed to look through the string. So I didn't need to care about the empty strings. For empty strings, it doesn't loop, it just return the default counter, in this case, `0`.

I just needed to loop through the `J` and for each character in the `J` string, I need to compare to each character of `S`. If they match, I increment the counter.

After looping through each character, just return the final counter.

``````def num_jewels_in_stones(J, S):
jewels = 0

for j in J:
for s in S:
if s == j:
jewels += 1

return jewels

print(num_jewels_in_stones("aA", "aAAbbbb")) # 3
print(num_jewels_in_stones("z", "ZZ")) # 0
``````

This is a `O(N^2)` solution in terms of time complexity. Or more precisaly: `O(len(J) * len(S))`. For the space complexity, it is `O(1)` as we just store the value in a counter. If `len(J)` or `len(S)` increase, the used space keeps constant.

Just to iterate this solution, we can make it `O(N)` in terms of time complexity by using a hash table to store all characters as key and the counter as value.

``````def num_jewels_in_stones_opt(J, S):
chars_counter = {}
counter = 0

for char in J:
if char in chars_counter:
chars_counter[char] += 1
else:
chars_counter[char] = 1

for char in S:
if char in chars_counter:
counter += chars_counter[char]

return counter

print(num_jewels_in_stones_opt("aA", "aAAbbbb")) # 3
print(num_jewels_in_stones_opt("z", "ZZ")) # 0
``````

So, for each `J`'s character. Verify if it is already in the `chars_counter`. If it is, just increment it. If not, initialize the counter.

Then, for each `S`'s character, verify if this character is in the `chars_counter`. If it is, get it and add to the `counter` variable. If not, do nothing.

After this iteration, we need the final value to the `counter`. Just return it.

As we said before, it runs in `O(N)`. Better than the first solution. But, for the worse case scenario, the space complexity is `O(N)`, worse than the first approach.

For more stories and posts about my journey learning & mastering software engineering, take a look at what I've been writing and documenting.