Lowest Common Ancestor of a BST
Bir ikili arama ağacı, tree dizisinde yığın sırasına göre saklanıyor: kök 0 indeksindedir, i indeksindeki düğümün çocukları 2*i+1 (sol) ve 2*i+2 (sağ) indekslerindedir ve -1 boş bir yeri belirtir. Bir düğümün sol alt ağacındaki her değer, düğümün değerinden küçüktür; sağ alt ağacındaki her değer ise daha büyüktür.
Ağaçta bulunan p ve q değerlerinin en düşük ortak atasının değerini döndüren lowestCommonAncestor fonksiyonunu yaz: her ikisini de alt ağacında bulunduran en derin düğüm. Bir düğüm kendi alt ağacının parçasıdır; bu nedenle p, q'nun üzerinde yer alıyorsa yanıt p'dir.
Fonksiyon
- treeinteger-array
- ikili arama ağacını düzey sırasına göre, boş konumlar için -1 kullanarak
- pinteger
- bulunacak ilk değer
- qinteger
- bulunacak ikinci değer
- Döndürürinteger
- Alt ağacında hem p hem de q bulunan en derin düğümün değeri
Kısıtlar
1 ≤ tree.length ≤ 32767- Her bir
tree[i],-1veya0 ≤ tree[i] ≤ 105değeridir. tree[0]hiçbir zaman-1değildir, dolayısıyla ağaçta 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. - Ağaç geçerli bir ikili arama ağacıdır, bu nedenle tüm değerleri birbirinden farklıdır.
pveq, ağaçtaki düğümlerin değerleridir. Herhangi bir sırada gelebilirler ve eşit olabilirler.
Örnekler
- Girdi
- tree = [20, 8, 31, 3, 12, 25, 40, -1, -1, 10, 15]p = 3q = 15
- Çıktı
- 8
- Açıklama
3ve15'ten yukarı çıkıldığında, ikisinin de ulaştığı ilk düğüm8'dir:3, onun sol çocuğudur ve15, sağındaki12'nin altındadır. Kök20de ortak bir atadır, ancak daha yukarıdadır.
- Girdi
- tree = [20, 8, 31, 3, 12, 25, 40, -1, -1, 10, 15]p = 12q = 10
- Çıktı
- 12
- Açıklama
10,12'nin sol çocuğudur ve bir düğüm kendi atası sayıldığından12her iki değeri de içerir ve onun altındaki hiçbir düğüm bunları içermez. Buradapdaha büyük değerdir.
- Girdi
- tree = [50, 30, 70, 20, 40, 60, 80, -1, -1, -1, -1, 55]p = 55q = 80
- Çıktı
- 70
- Açıklama
- Her iki değer de kök
50değerinden büyük, bu yüzden ikisi de onun sağında yer alır.70düğümünde yolları ayrılır:55daha küçüktür ve solunda,60değerinin altında yer alır;80ise daha büyüktür.
Ek soru
p veya q ağaçta bulunmayabilecek olsaydı ve bu durumda fonksiyonun -1 döndürmesi gerekseydi neyi değiştirirdin?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
Kök düğümde dur. Hem
phem deqonun değerinden küçükse, her iki düğüm de hangi alt ağaçtadır?Her iki değer de geçerli düğümün aynı tarafında olduğu sürece, daha aşağıdaki her ortak ata da o taraftadır. İkisinin aynı tarafta olmadığı ya da düğümün bu değerlerden birini içerdiği ilk düğüm, aradığın düğümdür.
0indeksinden başlayın. Her iki değer detree[i]değerinden küçükken2*i+1konumuna ilerleyin; her iki değer de büyükken2*i+2konumuna ilerleyin. Aksi hâldetree[i]değerini döndürün.
Çözüm
Bir arama ağacı, her düğümde bir değerin nerede bulunduğunu söyler: küçük değerler solda, büyük değerler sağda. Kökten başlayıp her iki değeri de barındıran tarafa doğru ilerle. Aynı tarafı paylaşmayı bıraktıkları ilk düğüm cevaptır ve ona tek bir yol izleyerek ulaşırsın.
Ağacın tamamını, sırayı dikkate almadan ara
Sezgi
Bu yöntem her ikili ağaçta çalışır. Özyinelemeli find(i), i düğümündeki alt ağacın ne içerdiğini bildirir. p veya q değerini içeren bir düğüm kendisini bildirir: diğer değer onun altındaysa yanıt odur; değilse daha yukarıdaki bir düğüm her ikisini de görür. Diğer tüm düğümler iki çocuğuna da sorar. İkisi de bir şey bildirirse, p ve q farklı taraflardadır ve bu düğüm buluştukları yerdir; yalnızca biri bildirirse, bunu yukarı iletir.
3 ve 15 için 8, solundan 3 indeksini ve sağından 10 indeksini alır ve kendisini bildirir. Her düğümü ziyaret edebilir: O(n) zaman ve özyineleme için O(h).
Algoritma
find(i)yaz.ikonumu boşsa (sondan sonraysa veya-1ise),-1döndür.tree[i],pveyaqiseidöndür.2*i+1ve2*i+2üzerindefindçağır. İkisi de bir şey bulduysaidöndür.- Aksi takdirde, bir şey bulan tarafı veya
-1döndür. tree[find(0)]döndür.
def lowestCommonAncestor(tree, p, q):
n = len(tree)
def find(i):
# In the subtree at index i: the index of the answer if both values are
# inside, the index of the one that is, or -1 when neither is.
if i >= n or tree[i] == -1:
return -1
if tree[i] == p or tree[i] == q:
return i
left = find(2 * i + 1)
right = find(2 * i + 2)
if left != -1 and right != -1:
return i # one value on each side: this node is the answer
return left if left != -1 else right
return tree[find(0)]İki arama yolunu karşılaştırın
Sezgi
Bir değeri her zamanki şekilde ara: kökten başla, değeri düğümden küçükse sola, büyükse sağa git. Kökten bir düğüme giden yol tektir; bu nedenle izlenen yol, değerin tüm atalarından ve başka hiçbir şeyden geçmez.
Her iki yolu da kaydet. Değerler farklı yönlere gidene kadar yollar aynı düğümleri paylaşır; bu nedenle ortak başlangıç, ortak ataları listeler ve son değer en aşağıdaki atadır. 3 ve 15 için yollar 20, 8, 3 ve 20, 8, 12, 15 şeklindedir: 20, 8 değerlerini paylaşırlar, dolayısıyla yanıt 8 olur. Her yol, seviye başına bir adım sürer: O(h) zaman ve listeler için O(h) alan.
Algoritma
path(target)yazın:0indeksinden başlayın,tree[i]değerini kaydedin, bu değertarget'a eşit olduğunda durun; aksi takdirdetargetdaha küçükse2*i+1indeksine, daha büyükse2*i+2indeksine geçin.p'ye giden yolu veq'ya giden yolu oluşturun.- Her iki listede de baştan başlayarak ilerleyin ve ortak olan son değeri döndürün.
def lowestCommonAncestor(tree, p, q):
def path(target):
# The values met on the way from the root down to target.
values = []
i = 0
while True:
values.append(tree[i])
if tree[i] == target:
return values
i = 2 * i + 1 if target < tree[i] else 2 * i + 2
to_p, to_q = path(p), path(q)
# Both paths start at the root; the answer is the last value they share.
answer = to_p[0]
for a, b in zip(to_p, to_q):
if a != b:
break
answer = a
return answerAyrılana kadar aşağı doğru ilerle
Sezgi
p ve q aynı yönde ilerlerken iki yol örtüşür; bu yüzden ikisini birlikte yürütün. v değerini tutan bir düğümde, her iki değer de daha küçükse ikisi de sol alt ağaçta bulunur ve v altındaki tüm ortak atalar da oradadır: sola gidin. Her ikisi de daha büyükse sağa gidin.
Aksi takdirde, değerlerden biri daha küçük, diğeri daha büyüktür; dolayısıyla v düğümünün hiçbir çocuğu ikisini birden içermez ya da değerlerden biri v'ye eşittir ve v onun kendi atasıdır. Her iki durumda da v, ikisinin de üzerindeki en derin düğümdür. Üçüncü örnekte 50, her iki değerin de altındadır; bu yüzden 70'e doğru sağa gidilir. Burada 55 daha küçük, 80 ise daha büyüktür. Her seviyede bir karşılaştırma çifti yapılması O(h) zaman ve O(1) alan gerektirir.
Algoritma
i = 0indeksinden başla.v = tree[i]değerini oku.p < vveq < vise2*i+1konumuna git ve tekrarla.p > vveq > vise2*i+2konumuna git ve tekrarla.- Aksi takdirde
vdeğerini döndür.
def lowestCommonAncestor(tree, p, q):
i = 0 # start at the root
while True:
value = tree[i]
if p < value and q < value:
i = 2 * i + 1 # both are smaller: the answer is on the left
elif p > value and q > value:
i = 2 * i + 2 # both are larger: the answer is on the right
else:
return value # they split here, or one of them is this node
Tuzaklar ve uç durumlar
- Hareket kontrollerinde
≤ve≥kullanmak.p = 12veq = 10iken, yürüyüş12'yi geçip10'a gider, ardından10'u döndürür veya ağacın dışına çıkar. p < qolduğunu varsaymak. İkinci örnektepdaha büyük değerdir. Her ikisini de düğüme göre kontrol edin veya önce yerlerini değiştirin.- Değer yerine indeksi döndürmek. Yanıt
ideğil,tree[i]'dir. - Lua ve R'de diziler 1'den başlar.
2*i+1aritmetiği için düğüm indekslerini 0 tabanlı tutun vetree[i + 1]değerini okuyun.
Sıkça sorulan sorular3
BST'de en düşük ortak atayı bulmanın zaman karmaşıklığı nedir?
Kökten yapılan yürüyüş tek bir yolu izler; bu nedenle derinliği h olan bir ağaçta O(h) zaman ve O(1) ek alan gerektirir. Dengeli bir ağaçta bu O(log n), tek bir yol şeklindeki ağaçta ise O(n) olur.
İkili arama ağacındaki LCA, ikili ağaçtaki LCA'dan nasıl farklıdır?
Sıradan bir ikili ağaçta bir değer herhangi bir yerde olabilir, bu yüzden O(n) işlem gerektiren her düğümü aramanız gerekebilir. Bir arama ağacında, iki değeri bir düğümle karşılaştırmak her birinin hangi tarafta olduğunu gösterir; böylece kökten başlayarak tek bir yolu izlersiniz.
Bir düğüm kendi en düşük ortak atası olabilir mi?
Evet. Bir düğüm kendisinin atası sayılır; bu nedenle p, q'nun üstündeyse yanıt p olur ve iki değer eşitse yanıt o değerdir.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
def lowestCommonAncestor(tree, p, q):
# Kodu buraya yazınTest #1
Test #2
Test #3
Argümanlar
tree = [20, 8, 31, 3, 12, 25, 40, -1, -1, 10, 15] p = 3 q = 15
Beklenen Çıktı
8