Maximum Depth of Binary Tree
Seviye sırasına göre tree dizisinde saklanan bir ikili ağaç veriliyor. Kök, 0 dizininde bulunur; i dizinindeki düğümün çocukları 2*i+1 (sol) ve 2*i+2 (sağ) dizinlerinde bulunur; -1 boş bir yeri belirtir ve dizinin sonunda fazladan -1 girdileri bulunabilir. Ağacın maksimum derinliğini döndürün: kökten bir yaprağa giden en uzun yoldaki düğüm sayısı.
Fonksiyon
- treeinteger-array
- ikili ağaç, seviye sırasına göre; boş konumlar için -1
- Döndürürinteger
- en uzun kökten yaprağa yol üzerindeki düğüm sayısı
Kısıtlar
1 ≤ tree.length ≤ 32767- Her
tree[i],-1veya0 ≤ tree[i] ≤ 1000koşulunu sağlayan bir değerdir. tree[0]hiçbir zaman-1değildir, bu nedenle ağacın en az bir düğümü vardır.- Dizi, son düğümden sonra fazladan
-1girdileriyle bitebilir. - Boş bir noktanın her iki çocuğu da boştur ve derinlik en fazla
14olur.
Örnekler
- Girdi
- tree = [5, 8, 1, -1, 3, -1, -1, -1, -1, 6]
- Çıktı
- 4
- Açıklama
- En uzun yol
5,8,3,6(0,1,4,9indeksleri) olup 4 düğüm içerir.1üzerinden geçen yol 2 düğümden sonra sona erer.
- Girdi
- tree = [7, -1, -1]
- Çıktı
- 1
- Açıklama
- İki
-1girdisi, kökün boş çocuk konumlarıdır. Kök tek başına bir düğümden oluşan bir yoldur, bu nedenle derinlik1'dir,0değil.
- Girdi
- tree = [2, -1, 9, -1, -1, -1, 4]
- Çıktı
- 3
- Açıklama
- Kök
2'nin sol çocuğu yoktur.2indeksindeki sağ çocuğu9'un sağ çocuğu,6indeksindeki4'tür; 3 düğümlü bir yol.
Gönderirken +13 gizli test
Ek soru
Kökten yaprağa en uzun yoldaki değerleri, yalnızca uzunluğunu değil, nasıl döndürürdünüz? Birkaç yol eşit uzunluktaysa hangisini döndürürdünüz ve bunu sözleşmede nasıl belirtirdiniz?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
Kökü düşün. Sol alt ağacının ve sağ alt ağacının derinliğini bilseydin, ağacın tamamının derinliği ne olurdu?
Kök için
1ile iki alt ağacın derinliklerinden büyük olanının toplamıdır; boş bir noktanın derinliği0'dır. Aynı kural her düğüm için geçerlidir, bu nedenle her düğümün derinliğini bilen bir dolaşım yanıtı bulabilir.- Kökü derinliği 1 olacak şekilde başlayarak, düğüm indeksi ve derinliğinden oluşan çiftleri bir yığında tut. Bir çifti çıkar, görülen en büyük derinliği hatırla ve dizi içinde bulunan ve
-1olmayan her çocuğu, derinliği bir artırılmış olarak2*i+1ve2*i+2konumlarına ekle.
Çözüm
Derinlik, tek başına en uzun dal tarafından belirlenir ve her düğüme bakmadan hangi dalın bu olduğunu anlayamazsın. Bu nedenle görev, her düğümde ne kadar derinde olduğunu bilen tam bir dolaşımdır. Özyineleme, seviye seviye genişlik öncelikli arama ve kendi yığınını kullanan derinlik öncelikli arama bunu tek geçişte yapar; bulundukları yeri takip etme biçimleri farklıdır.
İki alt ağaç üzerinde özyineleme
Sezgi
Önce dizide nasıl gezinileceğine bakalım. i dizinindeki düğümün sol çocuğu 2*i+1, sağ çocuğu ise 2*i+2 dizinindedir. Bir çocuk, yalnızca dizini dizi sınırları içindeyse ve o konumdaki değer -1 değilse gerçektir. [5, 8, 1, -1, 3, -1, -1, -1, -1, 6] dizisinde kök 5, 1 ve 2 dizinlerinde çocuklara sahiptir; 1 dizinindeki 8'in 3 dizininde boş bir sol konumu ve sağında 4 dizininde 3 vardır; bu 3'ün de altında, 9 dizininde 6 bulunur.
Şimdi fikre bakalım. Bir düğümden geçen en derin yol, iki alt ağacından hangisi daha derinse onun içine doğru ilerler. Dolayısıyla i dizinindeki alt ağacın derinliği, düğümün kendisi için 1 artı 2*i+1 ve 2*i+2 dizinlerindeki derinliklerden büyük olanıdır. Boş bir konumun derinliği 0'dır; bu da özyinelemeyi sonlandırır. Bir yaprak 1 + max(0, 0) = 1 değerini alır ve değerler köke doğru geri yükselir.
Her düğüm bir kez ziyaret edilir, bu nedenle zaman karmaşıklığı O(n)'dir. Çağrı yığını, geçerli yoldaki her seviye için bir çerçeve tutar; h derinlik olmak üzere bu O(h)'dir ve burada en fazla 14'tür. Bu sınır, özyinelemeyi bu problemde güvenli kılar. Uzun bir zincir şeklindeki işaretçi tabanlı bir ağaçta aynı kod, Python'da 1000 çerçeve olan özyineleme sınırına takılırdı.
Algoritma
depth(i)fonksiyonunu yazın:idizinin sonunu geçmişse veyatree[i]değeri-1ise0döndürün.- Aksi takdirde
1 + max(depth(2*i+1), depth(2*i+2))döndürün. depth(0)döndürün.
def maxDepth(tree):
def depth(i):
# An index past the end or a -1 is an empty spot: depth 0.
if i >= len(tree) or tree[i] == -1:
return 0
return 1 + max(depth(2 * i + 1), depth(2 * i + 2))
return depth(0)Genişlik öncelikli arama, seviye seviye
Sezgi
Maksimum derinlik, ağaçtaki seviye sayısıdır; bu nedenle yolları takip etmek yerine seviyeleri sayabilirsiniz. Bir kuyruk, düğümleri seviye sırasına göre ziyaret eder: kuyruğu kökle başlatın ve her düğümü kuyruktan çıkardığınızda, gerçek çocuklarını kuyruğun sonuna ekleyin.
Seviyeleri saymak için kuyruğu gruplar hâlinde işleyin. Her gruptan önce kuyruğun kaç düğüm içerdiğine bakın. Bunlar tam olarak bir seviyenin düğümleridir; çünkü grup sırasında eklediğiniz çocuklar bu düğümlerin arkasına gelir. Bu kadar düğümü çıkarın, çocuklarını kuyruğa ekleyin ve derinliğe 1 ekleyin. Kuyruk boşaldığında derinlik, grup sayısıdır. İlk örnekte gruplar [5], [8, 1], [3] ve [6] olduğundan yanıt 4 olur.
Her düğüm kuyruğa bir kez girer ve kuyruktan bir kez çıkar; zaman karmaşıklığı O(n) olur. Kuyruk, bir seferde tek bir seviyeyi tutar; en geniş seviye w için alan karmaşıklığı O(w) olur. Tam bir ağaçta en alt seviye, 14 derinliğinde toplam 16383 düğümün yaklaşık yarısı olan 8192 düğümü içerir.
Algoritma
- Kök dizini
0kuyruğa koy vedepth = 0olarak ayarla. - Kuyruk boş olmadığı sürece
depthdeğerini1artır ve kuyruğun boyutunu oku. - Bu sayıda dizini kuyruktan çıkar. Her biri için, dizi içinde olan ve
-1olmayan çocuk dizinlerini2*i+1ve2*i+2kuyruğa ekle. - Kuyruk boşaldığında
depthdeğerini döndür.
from collections import deque
def maxDepth(tree):
n = len(tree)
queue = deque([0])
depth = 0
while queue:
depth += 1
for _ in range(len(queue)): # exactly the nodes of this level
i = queue.popleft()
for child in (2 * i + 1, 2 * i + 2):
if child < n and tree[child] != -1:
queue.append(child)
return depthBelirgin bir yığın kullanarak derinlik öncelikli arama
Sezgi
Özyinelemenin yaptığı gibi yolları takip edebilirsin; bunun için tek bir özyinelemeli çağrı bile yapman gerekmez. Kendi yığınını tut ve her düğümü derinliğiyle birlikte sakla; çünkü başka hiçbir şey onun ne kadar aşağıda olduğunu hatırlamaz. (0, 1) çiftiyle başla: kök, derinliği 1.
Bir çifti çıkar, derinliğini şimdiye kadar görülen en iyi değerle karşılaştır ve her gerçek çocuğu depth + 1 ile yığına ekle. Ağaçtaki her düğüm, ona ulaşan yolun uzunluğunu taşıyarak tam bir kez yığına eklenir; dolayısıyla çıkardığın en büyük derinlik yanıttır. İlk örnekte, 9 indeksindeki 6, (9, 4) olarak eklenir ve hiçbir çift daha derine inmez.
Zaman karmaşıklığı O(n)’dir. Yığın, geçerli yol boyunca bekleyen kardeş düğümleri tutar; her seviye için en fazla yaklaşık bir tane olduğundan alan karmaşıklığı O(h)’dir. Bu, özyinelemeyle aynıdır ancak taşabilecek bir çağrı yığını kullanmaz. Bir ağaç derin olabilecekse bu sürümü tercih et; ayrıca bu yaklaşım işaretçi tabanlı ağaçlara da değişmeden uygulanabilir.
Algoritma
(0, 1)değerini bir yığına ekle vebest = 0olarak ayarla.(i, depth)çiftini yığından çıkar vebestdeğerinibestiledepthdeğerlerinden büyük olanına ayarla.- Dizi içinde bulunan ve
-1olmayan her2*i+1ve2*i+2çocuk indeksi için, onudepth + 1ile birlikte yığına ekle. - Yığın boşalana kadar tekrarla, ardından
bestdeğerini döndür.
def maxDepth(tree):
n = len(tree)
best = 0
stack = [(0, 1)] # (node index, depth of that node); the root is never empty
while stack:
i, depth = stack.pop()
best = max(best, depth)
for child in (2 * i + 1, 2 * i + 2):
if child < n and tree[child] != -1:
stack.append((child, depth + 1))
return best
Tuzaklar ve uç durumlar
Bu problemdeki yanlış yanıtların çoğu, bir eksik sayımından veya boş bir yeri düğüm olarak değerlendirmekten kaynaklanır.
- Düğümler yerine kenarları saymak. Burada tek bir düğümün derinliği
1olur; bunun için0döndürmek ya da 4 düğümlü bir yol için3döndürmek bir eksik saymaktır. - Sınır kontrolünü atlamak. Dizinin sonuna yakın bir yaprak, son düğümden hemen sonra bitebileceği için dizideki son indisi aşan çocuk indislerine sahip olabilir.
tree[child]değerini okumadan öncechild < nkontrolünü yapın. - Derinliği dizinin uzunluğundan çıkarmak. Dizinin sonunda fazladan
-1girdileri olabilir; bu nedenle uzunluğu, gerçek düğümlerin bulunduğu en derin seviyeden daha derin bir seviyeye karşılık gelebilir. -1değerini bir değer olarak değerlendirmek. Bu, eksik bir düğümü belirtir; bu nedenle yığına eklenmemeli, kuyruğa alınmamalı veya sayılmamalıdır.- Ağacın dengeli olduğunu varsaymak. Yanıt, her sağ konumun boş olduğu 14 düğümlü sol zincirde olduğu gibi, en uzun dalı izler.
- Genişlik öncelikli sürümde, döngünün içinde kuyruk boyutunu okumak. Çocuklar eklendikçe boyut değişir; bu yüzden toplu işlem başlamadan önce boyutu kaydedin.
- Dizilerin 1'den başladığı Lua ve R'de ofseti karıştırmak.
2*i+1hesabı için düğüm indislerini 0 tabanlı tutun vetree[i + 1]değerini okuyun.
Sıkça sorulan sorular4
İkili Ağacın Maksimum Derinliğinin zaman karmaşıklığı nedir?
Her yaklaşım her düğümü bir kez ziyaret eder, bu nedenle zaman karmaşıklığı O(n)'dir. Derinlik öncelikli sürümler, keşfedilen yol için O(h) ek alan kullanır; burada h derinliktir. Genişlik öncelikli sürüm, en geniş seviye için O(w) alan kullanır; bu, tam bir ağaçta düğümlerin yaklaşık yarısı olabilir.
İkili ağacın maksimum derinliğini bulmak için DFS mi yoksa BFS mi kullanmalısınız?
İkisi de O(n) sürede doğru yanıtı verir. Derinlik öncelikli aramanın yazımı daha kısadır ve derinlikle orantılı bellek kullanır; bu nedenle geniş ve sığ ağaçlar için uygundur. Genişlik öncelikli arama seviyeleri doğrudan sayar ve en geniş seviyedeki düğüm sayısıyla orantılı bellek kullanır; bu nedenle derin ve dar ağaçlar için uygundur. Minimum derinliği bulmak için BFS avantajlıdır, çünkü karşılaştığı ilk yaprakta durabilir.
İkili bir ağacın maksimum derinliğini özyineleme kullanmadan nasıl bulursunuz?
Bir düğüm ve derinliğinden oluşan çiftler için açık bir yığın kullanın. Kökü derinlik 1 ile başlatın, bir çifti yığından çıkarın, derinliğini kaydedin ve her çocuğu derinliğinin bir fazlasıyla yığına ekleyin. Yığından çıkardığınız en büyük derinlik cevaptır. Her seviye birer birer işlenen bir kuyruk da işe yarar; her seviye için bir artırın.
İkili ağacın derinliği ile yüksekliği arasındaki fark nedir?
Bir düğümün derinliği, kökten ona kadar olan adım sayısını; bir düğümün yüksekliği ise ondan en derin yaprağa kadar olan adım sayısını ifade eder. Ağacın maksimum derinliği ile kökün yüksekliği aynı sayıdır. Bu problem düğümleri sayar, bu nedenle tek bir düğümün derinliği 1 olur; bazı kitaplar bunun yerine kenarları sayar ve bu da bir eksik verir.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
Python
def maxDepth(tree):
# Kodu buraya yazınDurum 1
Durum 2
Durum 3
Girdi
tree = [5, 8, 1, -1, 3, -1, -1, -1, -1, 6]
Beklenen
4