Alien Dictionary
Bir sözcük listesi, bilmediğiniz bir alfabeye göre sıralanmıştır: gizli bir sıradaki 26 küçük İngilizce harf. Sözcükler alışıldığı gibi karşılaştırılır. İki sözcüğün farklı olduğu ilk konum belirleyicidir; bir sözcük diğerinin başlangıcıysa kısa olan önce gelir.
Sözcüklerde yer alan harfleri, alfabe sırasına göre tek bir dize olarak döndürün. Birden fazla sıralama uygunsa, sözlükte alışılmış sıraya göre önce geleni döndürün. Hiçbir sıralama uygun değilse "invalid" döndürün.
Fonksiyon
- wordsstring-array
- bilinmeyen alfabeye göre sıralanmış sözcükler
- Döndürürstring
- uygun olan en küçük sıradaki harfler ya da "geçersiz"
Kısıtlar
1 ≤ words.length ≤ 50001 ≤ words[i].length ≤ 10- Her sözcük yalnızca küçük İngilizce harfler içerir.
- Aynı sözcük birden fazla kez görünebilir.
Örnekler
- Girdi
- words = ["tea", "ten", "ate", "act", "cat"]
- Çıktı
- "etacn"
- Açıklama
tea,ten'den önce geldiğinde a'yı n'den önce yerleştirir. Diğer çiftler t'nin a'dan, t'nin c'den ve a'nın c'den önce geldiğini gösterir. Hiçbir kural e'den söz etmediği için en küçük sıralama e ile başlar: e, t, a, c, n.
- Girdi
- words = ["bat", "tab", "tub", "bus"]
- Çıktı
- "invalid"
- Açıklama
bat,tab'den önce geldiğinde b'yi t'den önce koyar;tub,bus'tan önce geldiğinde ise t'yi b'den önce koyar. İkisi birden doğru olamaz, bu yüzden hiçbir sıralama uymaz.
- Girdi
- words = ["cooking", "cook"]
- Çıktı
- "invalid"
- Açıklama
cook,cookingsözcüğünün başlangıcıdır; bu nedenle her alfabede önce gelir. Liste onu ikinci sıraya koyuyor; harflerin hiçbir sıralaması bunu açıklayamaz.
Ek soru
Uydurma sırasının tek seçenek olup olmadığını nasıl anlarsınız?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
teavetengibi yan yana duran iki kelimeye bakın. Alfabe hakkında size ne söylerler ve hangi konuları açık bırakırlar?Yan yana olan bir çift en fazla bir kural verir: kelimelerin farklı olduğu ilk konumda, ilk kelimenin harfi ikinci kelimenin harfinden önce gelir. Kurallar, harfler üzerinde bir grafiğin kenarlarıdır ve yanıt, her kenara uyan bir sıralamadır. Farklı konumu olmayan ve ilk kelimenin daha uzun olduğu bir çifte dikkat et.
Kahn algoritmasını kullan: Kendisine yönelen kuralı olmayan bir harfi yerleştir, o harfin kurallarını kaldır ve tekrarla. Hazır harfleri bir min-heap'te tut ve her zaman en küçük olanı yerleştir. Bazı harfler hiç yerleştirilmezse kurallar bir döngü içerir.
Çözüm
Komşu sözcüklerin her çifti, farklı oldukları ilk konumda en fazla bir kural verir: x harfi, y harfinden önce gelir. Uygun bir sıralama, bu kuralların topolojik sıralamasıdır. Bir döngü ya da bir sözcüğün kendi ön ekinden önce yerleştirilmesi, listeyi olanaksız kılar. Hazır harfler arasından her zaman en küçüğünü seçen bir min-yığın, en küçük sıralamayı verir.
Harflerin her sıralamasını dene
Doğru, ama en büyük testlerde bitmiyor
Sezgi
Komşu her çifti kontrol ederek k farklı harfin bir sıralamasını test edin. İlk farklı konumda ilk sözcüğün harfi daha önce gelmelidir; hiç fark yoksa ilk sözcük daha uzun olmamalıdır. Sıralamaları alfabetik olandan başlayarak next permutation ile artan sırada gezin ve koşulu sağlayan ilk sıralama, uygun olan en küçük sıralamadır.
k harfin k! sıralaması vardır: 10 harf için 3,628,800, 26 harf içinse yaklaşık 4 × 10^26 sıralama bulunur ve her test en fazla 5 × 10^4 karakter okur. Hiçbir sıralama koşulu sağlamadığında arama hepsini dener.
Algoritma
- Farklı harfleri topla ve alfabetik olarak sırala.
- Mevcut dizilimde her harfin sırasını kaydet.
- Komşu her çifti kontrol et: ilk farklı konumda ilk kelimenin harfi daha küçük sıraya sahip olmalı; fark yoksa ilk kelime daha uzun olmamalı.
- Tüm çiftler koşulu sağlıyorsa dizilimi döndür; aksi hâlde bir sonraki daha büyük dizilime geç.
- Bir sonraki dizilim yoksa
"invalid"döndür.
from itertools import permutations
def fits(words, rank):
# The list is sorted under rank when every neighbouring pair is in order.
for first, second in zip(words, words[1:]):
for x, y in zip(first, second):
if x != y:
if rank[x] > rank[y]:
return False
break
else:
# One word starts the other: the shorter must come first.
if len(first) > len(second):
return False
return True
def alienOrder(words):
letters = sorted(set("".join(words)))
# permutations() of a sorted list yields the orders from smallest to largest,
# so the first order that fits is the answer.
for order in permutations(letters):
rank = {ch: i for i, ch in enumerate(order)}
if fits(words, rank):
return "".join(order)
return "invalid"Kahn algoritması ve min-yığın
Sezgi
Komşu bir çiftte yalnızca ilk farklılık önemlidir: act sözcüğünün cat sözcüğünden önce gelmesi, a harfinin c harfinden önce geldiğini söyler ve ondan sonraki harfler asla karşılaştırılmaz. Bu nedenle her çift en fazla bir kenar oluşturur.
Kahn algoritması, kenarları bir sıralamaya dönüştürür: her harfin gelen kenarlarını say, sayısı 0 olan bir harfi sıraya ekle, o harfin çıkan kenarlarını kaldır ve işlemi tekrarla. Bir döngüdeki harfin, döngüde kendisinden önce gelen harften gelen bir kenarı her zaman kalır; bu nedenle o harf asla sıraya eklenmez. Görünen harf sayısından daha az harf sıraya eklenirse yanıt "invalid" olur.
Sıraya hazır harfleri bir min-heap'te tut ve en küçüğünü sıraya ekle. Uygun herhangi bir sıralama hazır bir harfle başlar; dolayısıyla bu, mümkün olan en küçük ilk harftir ve onu sıraya eklemek yalnızca kenarları kaldırdığı için başka hiçbir harfi engellemez. İlk örnekte e ve t başlangıçta hazırdır ve önce e gelir. Sıradan bir kuyruk geçerli bir sıralama verir, ancak bu sıralama her zaman en küçük sıralama olmaz.
Algoritma
- Kelimelerde geçen her harfi işaretle.
- Her komşu çifti için, farklı olan ilk konumu bul ve iki harfi arasına kenarı bir kez ekle. Fark yoksa ve ilk kelime daha uzunsa
"invalid"döndür. - Gelen kenarları say ve sayısı 0 olan işaretli her harfi bir min-yığına ekle.
- En küçük harfi çıkar ve sona ekle. Gösterdiği her harfin sayısını azalt ve 0'a ulaşanları yığına ekle.
- Tüm işaretli harfler yerleştirildiyse yerleştirilen harfleri, aksi hâlde
"invalid"döndür.
import heapq
def alienOrder(words):
# Letters are numbered 0 for 'a' up to 25 for 'z'.
present = [False] * 26
for word in words:
for ch in word:
present[ord(ch) - 97] = True
# before[a][b] is True once you know letter a comes before letter b.
before = [[False] * 26 for _ in range(26)]
indegree = [0] * 26
for first, second in zip(words, words[1:]):
for x, y in zip(first, second):
if x != y:
# Only the first difference tells you anything.
a, b = ord(x) - 97, ord(y) - 97
if not before[a][b]:
before[a][b] = True
indegree[b] += 1
break
else:
# No difference: one word starts the other, so the shorter must come first.
if len(first) > len(second):
return "invalid"
# A min-heap of the letters with nothing left before them.
heap = [c for c in range(26) if present[c] and indegree[c] == 0]
heapq.heapify(heap)
order = []
while heap:
c = heapq.heappop(heap)
order.append(chr(c + 97))
for nxt in range(26):
if before[c][nxt]:
indegree[nxt] -= 1
if indegree[nxt] == 0:
heapq.heappush(heap, nxt)
# A letter on a cycle never gets down to indegree 0, so it is never placed.
if len(order) < sum(present):
return "invalid"
return "".join(order)
Tuzaklar ve uç durumlar
- Bir sözcük çiftinden birden fazla kural çıkarmak.
actvecatsözcüklerinin ikinci konumunu okumak, c’nin a’dan önce gelmesini ekler ve ilk örneği sahte bir döngüye dönüştürür. - Önek tuzağını gözden kaçırmak.
cookingsözcüğücooksözcüğünden önce geldiğinde farklı bir harf yoktur; bu yüzden yalnızca farklılıkları ele alan bir döngü bir sıralama döndürür. - Hiçbir kuralda geçmeyen harfleri dışarıda bırakmak. İlk örnekte hiçbir kural e harfinden söz etmez, ancak e yine de yanıtta yer almalıdır.
- Tekrarlanan bir kuralı, giriş derecesinde iki kez sayıp yalnızca bir kez saklamak. Harfin giriş derecesi hiçbir zaman 0 olmaz ve geçerli bir liste döngü olarak bildirilir.
- Yan yana duran iki eşit sözcüğü önek tuzağı olarak değerlendirmek; yinelenen bir sözcük sıralamayı bozmaz.
Sıkça sorulan sorular3
Alien Dictionary'nin zaman karmaşıklığı nedir?
O(C + k²); burada C toplam karakter sayısı, k ≤ 26 ise farklı harflerin sayısıdır. Liste üzerinde tek bir geçiş, ilk farklılıkların tümünü bulur ve Kahn algoritması en fazla k² kenarı ziyaret eder. Kenar tablosu O(k²) alan kullanır.
Neden yalnızca komşu sözcükleri karşılaştırıyoruz?
Sıralı olma geçişlidir: Her sözcük kendisinden sonrakinden küçük ya da ona eşitse, listenin tamamı sıralıdır. Dolayısıyla, aralarında uzaklık bulunan iki sözcükten çıkarabileceğin her kural, zaten bu sözcüklerin arasındaki komşu çiftlerden de çıkar.
Bir sözcüğün kendi önekinden önce gelmesi neden geçersizdir?
Her alfabede bir sözcük kendi önekinden sonra gelir; çünkü karşılaştırma, bir fark bulmadan önce kısa olan sözcükteki harfleri tüketir. Kurallar arasında hiçbir döngü olmadan bir listenin imkânsız olmasının tek yolu budur.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
def alienOrder(words):
# Kodu buraya yazınTest #1
Test #2
Test #3
Argüman
words = ["tea", "ten", "ate", "act", "cat"]
Beklenen Çıktı
"etacn"