Jewels and Stones

def jewel_count(stones, jewels):
    stones, jewels = sorted(stones), sorted(jewels)

    count, i, j = 0, 0, 0
    while i < len(stones) and j < len(jewels):
        if stones[i] == jewels[j]:
            count += 1
            i += 1
        elif stones[i] < jewels[j]:
            i += 1
        else:
            j += 1
    return count

#Challenge

SourceLanguage
DailyBytepython

Given a string listing kinds of jewels and a string listing the kinds of stones you own, return the number of stones you have that're also jewels.

#Solution

We sort both strings and then we place two markers at the beginning of each string, iterating through them in tandom. Once we're at a jewel that's also a stone, we increment our jewel count and push the stone marker forward. Otherwise when our stone marker is less than our jewel marker we know we'll never encounter a jewel worth less than our current stone and safely push the stone marker forward. Otherwise we push the jewel marker forward because we need to find a jewel worth at least as much as our stone.

#Test Cases

jewel_count("ac", "abc") # 2
jewel_count("AaaddfFf", "Af") # 3
jewel_count("AYOPD", "ayopd") # 0

#Alternative Implementation

Convert the jewel string to a set \(\mathcal{O}(j)\) and then for each character in the stones string, count if its in the jewel set. Checking for the presence of a string in a set takes \(\mathcal{O}(1)\) time so total time complexity adds up to \(\mathcal{O}(j+s)\)

def jewel_count(stones, jewels):
    return sum(1 for s in stones if s in set(jewels))