Jewels and Stones
Otrzymujesz dwa ciągi liter. Każda litera w jewels oznacza jeden rodzaj klejnotu, a żadna litera się nie powtarza. Każda litera w stones oznacza jeden posiadany przez ciebie kamień. Zwróć liczbę swoich kamieni, które są klejnotami. Wielkość liter ma znaczenie: "a" i "A" oznaczają różne rodzaje.
Funkcja
- jewelsstring
- rodzaje kamieni uznawanych za klejnoty, po jednej literze z każdego
- stonesstring
- posiadane przez ciebie kamienie, po jednej literze na każdy
- Zwracainteger
- liczba kamieni, których litera występuje w klejnotach
Ograniczenia
1 ≤ jewels.length ≤ 521 ≤ stones.length ≤ 104- Oba ciągi zawierają wyłącznie angielskie litery, małe i wielkie.
- Wszystkie litery w
jewelssą różne.
Przykłady
- Wejście
- jewels = "rR"stones = "rubyRRr"
- Wyjście
- 4
- Wyjaśnienie
- Rodzaje klejnotów to
riR. WrubyRRrkamienier,R,Rirpasują, au,biynie, więc odpowiedzią jest4.
- Wejście
- jewels = "z"stones = "ZZZ"
- Wyjście
- 0
- Wyjaśnienie
- Jedynym rodzajem klejnotu jest małe
z. Każdy kamień to wielkieZ, inny rodzaj, więc żaden z nich się nie liczy.
+12 ukrytych testów przy wysłaniu
Podpowiedzi
Otwieraj je po kolei. Każda zdradza trochę więcej.
W przypadku jednego kamienia, jakie pytanie decyduje o tym, czy się liczy?
Pytasz „czy ta litera jest klejnotem?” raz dla każdego kamienia. Jaka struktura odpowiada na to pytanie w stałym czasie?
Umieść litery z
jewelsw zbiorze, a następnie przejdź postonesi policz każdą literę, która znajduje się w zbiorze. Zachowaj wielkość liter.
Rozwiązanie
W przypadku każdego kamienia potrzebujesz jednej odpowiedzi: czy ta litera jest klejnotem? Wyszukiwanie w ciągu jewels dla każdego kamienia powtarza wciąż to samo przeszukiwanie. Umieść litery klejnotów w zbiorze, a każdy kamień będzie wymagał tylko jednego wyszukania.
Skanuj klejnoty w poszukiwaniu każdego kamienia
Intuicja
Bierz kamienie po jednym. Dla każdego kamienia przejdź przez jewels i zatrzymaj się przy pierwszej literze, która jest mu równa. Dopasowanie dodaje 1 do licznika. W pierwszym przykładzie kamień u jest porównywany z r i R, niczego nie znajduje i niczego nie dodaje.
Możesz zatrzymać się przy pierwszym dopasowaniu, ponieważ litery oznaczające rodzaje klejnotów są różne, więc kamień może pasować najwyżej do jednego z nich. Kamień, który nie jest klejnotem, trzeba porównać z każdą literą oznaczającą klejnot, zanim się o tym przekonasz.
Przy j rodzajach klejnotów i s kamieniach potrzeba do j × s porównań. Tutaj j ≤ 52, więc nawet 10^4 kamieni wymaga około 5 × 10^5 porównań, a skanowanie kończy się na czas. Nieefektywność staje się widoczna, gdy lista rodzajów się powiększa: to samo wyszukiwanie jest powtarzane dla każdego kamienia.
Algorytm
- Ustaw
countna0. - Dla każdego kamienia porównaj go z każdą literą w
jewels. - Po znalezieniu pierwszej pasującej litery dodaj
1docounti przejdź do następnego kamienia. - Zwróć
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 countUmieść klejnoty w zbiorze
Intuicja
Odpowiedź na pytanie „czy ta litera jest klejnotem?” jest taka sama za każdym razem, gdy zadasz je dla tej samej litery. Odpowiedz więc na nie raz dla każdego rodzaju: utwórz zbiór z liter w jewels. Zbiór sprawdza przynależność w stałym czasie, więc sprawdzenie każdego kamienia wymaga jednego wyszukania zamiast skanowania.
W pierwszym przykładzie zbiór to {r, R}. Podczas przechodzenia po rubyRRr wyniki wyszukiwania to: tak, nie, nie, nie, tak, tak, tak — cztery klejnoty. Utworzenie zbioru wymaga j kroków, a przejście po literach — s, więc łączna złożoność to O(j + s).
Zbiór zawiera najwyżej 52 litery. W języku bez wbudowanego zbioru to samo zadanie można wykonać za pomocą tablicy flag indeksowanej kodem znaku.
Algorytm
- Utwórz zbiór zawierający każdą literę z
jewels. - Ustaw
countna0. - Dla każdego kamienia dodaj
1docount, jeśli zbiór go zawiera. - Zwróć
count.
def numJewelsInStones(jewels, stones):
kinds = set(jewels)
count = 0
for stone in stones:
if stone in kinds:
count += 1
return count
Pułapki i przypadki brzegowe
Algorytm składa się z jednej pętli. Błędne odpowiedzi wynikają ze sposobu porównywania i zliczania liter.
- Ignorowanie wielkości liter. Zamiana obu ciągów na małe litery sprawia, że
zpasuje doZ, a drugi przykład zwraca3zamiast0. - Zliczanie różnych rodzajów klejnotów zamiast kamieni.
rubyRRrzawiera dwa rodzaje klejnotów, ale cztery kamienie będące klejnotami; liczy się każdy kamień, także powtórzenia. - Tworzenie zbioru wewnątrz pętli przechodzącej po kamieniach. Odtwarzanie go dla każdego kamienia kosztuje za każdym razem
jkroków i przywraca złożoność skanowaniaO(j × s). Utwórz go raz, przed pętlą. - Zamiana argumentów miejscami. Zbiór musi zawierać
jewels, a pętla musi przechodzić postones. Po odwróceniu tych ról drugi przykład zlicza jeden rodzaj klejnotuzwśród kamieni i nadal zwraca0, ale("a", "aaa")zwraca1zamiast3.
Najczęstsze pytania3
Jaka jest złożoność czasowa problemu „Jewels and Stones”?
W przypadku zbioru jest to O(j + s): j kroków, aby utworzyć zbiór z jewels, oraz jedno wyszukiwanie o stałym czasie dla każdego z s kamieni. Przeszukiwanie jewels dla każdego kamienia ma złożoność O(j × s).
Dlaczego warto użyć zbioru haszującego do rozwiązania problemu Klejnotów i kamieni?
Każdy kamień zadaje to samo pytanie: czy jego litera jest klejnotem. Zbiór haszujący odpowiada na nie w stałym czasie, podczas gdy przeszukiwanie ciągu jewels zajmuje czas proporcjonalny do jego długości. Płacisz raz za utworzenie zbioru i oszczędzasz przy każdym kolejnym kamieniu.
Czy potrafisz rozwiązać to bez zbioru?
Tak. Litery są literami angielskimi, więc tablica 128 lub 256 flag indeksowanych kodem znaku działa jak zbiór bez żadnego haszowania. Oznacz każdą literę klejnotu, a następnie policz kamienie, których flaga jest ustawiona. stones.count(jewels) w Ruby wykonuje całą pracę jednym wywołaniem, ale tablica flag pokazuje, co dzieje się pod spodem.
Podobne zadania
Zadania oparte na tych samych pomysłach. Rozwiązanie dwóch lub trzech utrwala schemat.
Python
def numJewelsInStones(jewels, stones):
# Wpisz kod tutajPrzypadek 1
Przypadek 2
Wejście
jewels = "rR" stones = "rubyRRr"
Oczekiwane
4