Validate Binary Search Tree
Seviye sırasına göre tree dizisinde saklanan bir ikili ağaç alıyorsun. Kök 0 indeksinde bulunur, i indeksindeki düğümün çocukları 2*i+1 (sol) ve 2*i+2 (sağ) indekslerinde bulunur, -1 boş bir konumu belirtir ve dizinin sonunda fazladan -1 girdileri olabilir.
Ağaç bir ikili arama ağacıysa true, değilse false döndüren isValidBST adlı bir fonksiyon yaz. İkili arama ağacında her düğümün değeri, sol alt ağacındaki tüm değerlerden kesinlikle büyük ve sağ alt ağacındaki tüm değerlerden kesinlikle küçüktür. Eşit iki değer hiçbir zaman geçerli bir ağaçta birlikte bulunamaz.
Fonksiyon
- treeinteger-array
- ikili ağaçta seviye sırasına göre, boş bir konum için -1
- Döndürürboolean
- ağaç bir ikili arama ağacıysa true, değilse false
Kısıtlar
1 ≤ tree.length ≤ 32767- Her
tree[i],-1veya0 ≤ tree[i] ≤ 105koşulunu sağlayan bir değerdir. 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. - Değerler tekrarlanabilir.
Örnekler
- Girdi
- tree = [8, 3, 12, 1, 6, 10, 15]
- Çıktı
- true
- Açıklama
- Her düğüm, üstündeki her düğümün doğru tarafında yer alır. Sırayla (sol alt ağaç, düğüm, sağ alt ağaç) okunduğunda değerler
1, 3, 6, 8, 10, 12, 15şeklinde, kesin olarak artan sırada gelir; arama ağacı da bunu sağlar.
- Girdi
- tree = [10, 5, 15, -1, -1, 6, 20]
- Çıktı
- false
- Açıklama
- Her düğüm sol çocuğundan büyük ve sağ çocuğundan küçüktür, ancak ağaç geçerli değildir.
5indeksindeki6, kök10düğümünün sağ alt ağacında yer alır; bu nedenle10'dan büyük olmalıdır, ancak değildir.
- Girdi
- tree = [12, 7, 12]
- Çıktı
- false
- Açıklama
- Kökün sağ çocuğu, kökle aynı değer olan
12değerini içerir. Sağ alt ağaç kesinlikle daha büyük olmalıdır; bu nedenle eşit bir değer kuralı bozar.
Gönderirken +16 gizli test
Ek soru
i indeksindeki düğümün ebeveyni, aşağı yuvarlanmış (i-1)/2 konumundadır. Yığın tutmadan veya özyineleme kullanmadan, bunun yerine ebeveynler arasında ilerleyerek ağacı sıralı biçimde O(1) ek alanla dolaşabilir misin?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
[10, 5, 15, -1, -1, 6, 20]içinde her düğüm sol çocuğundan büyük ve sağ çocuğundan küçüktür. Peki neden yine de bir ikili arama ağacı değildir?Her ata, bir düğüme bir sınır koyar: düğüm solundaysa altına, sağındaysa üstüne. Bu sınırlar birlikte açık bir aralık oluşturur.
vdeğerinden sola gitmek üst sınırıvdeğerine düşürür; sağa gitmek alt sınırıvdeğerine yükseltir.Kökten başlayarak ve izin verilen her değerden daha geniş bir aralık kullanarak
(index, low, high)öğelerinden oluşan bir yığın tut. Bir öğeyi çıkar, değer aralığın kesinlikle içinde değilse başarısız ol ve her gerçek çocuk için daraltılmış aralığıyla bir öğe ekle.
Çözüm
Kural, bir düğüm ve onun iki çocuğuyla değil, alt ağaçların tamamıyla ilgilidir. Bir ağaç her düğümde ebeveyn ve çocuk testini geçmesine rağmen yine de hatalı olabilir; çünkü derinlerdeki bir düğüm, birkaç seviye yukarıdaki bir atasının belirlediği sınırı aşabilir. Bunu temiz bir şekilde ele alan iki fikir vardır: ağacı sıralı biçimde dolaşıp değerlerin kesin olarak arttığını kontrol etmek veya her düğüme atalarının izin verdiği değer aralığını iletip düğümü bu aralığa göre kontrol etmek.
Her düğümü tüm alt ağaçlarıyla karşılaştırın
Sezgi
Önce, dizi içinde nasıl gezineceğimize bakalım. i indeksindeki düğümün sol çocuğu 2*i+1, sağ çocuğu ise 2*i+2 indeksindedir. Bir çocuk ancak indeksi dizinin içindeyse ve oradaki değer -1 değilse gerçektir. [10, 5, 15, -1, -1, 6, 20] dizisinde kök 10’un 1 ve 2 indekslerinde 5 ve 15 çocukları vardır; 15 düğümünün ise 5 ve 6 indekslerinde 6 ve 20 çocukları vardır.
Çoğu kişinin denediği ilk fikir, her düğümü yalnızca iki çocuğuyla karşılaştırır. Bu ağaç, bunun neden başarısız olduğunu gösterir: 5 < 10, 15 > 10, 6 < 15 ve 20 > 15 koşullarının hepsi sağlanır, ancak 6, 10 düğümünün sağında yer alır. Tanım, bir alt ağaçtaki her değerden söz eder; bu yüzden tam olarak bunu kontrol edin.
v değerini tutan bir düğüm için, solundaki her şeyin v değerinden küçük olması, solundaki en büyük değerin v değerinden küçük olmasına denktir. Aynı şekilde, sağındaki her şeyin v değerinden büyük olması, oradaki en küçük değerin v değerinden büyük olmasına bağlıdır. İki küçük özyinelemeli yardımcı işlev bu en büyük ve en küçük değerleri bulur. Bir taraf boşsa en büyük değer -1, en küçük değer ise 100001 olur. Bunlar izin verilen aralığın dışında kalan değerlerdir; bu nedenle boş bir taraf hiçbir zaman koşulu bozmaz.
Bu yöntem doğrudur, ancak aynı işi tekrarlar. Bir düğüm, üzerindeki her ata için bir kez taranır; dolayısıyla derinliği h olan bir ağaçta toplam ziyaret sayısı yaklaşık n × h olur. Derinlik en fazla 14 olduğunda bu yöntem burada uygundur, ancak n düğümden oluşan tek uzun bir yol biçimindeki ağaçta bu sayı O(n²) düzeyine çıkar.
Algoritma
- Değeri
-1olmayan heriindeksini gözden geçir. 2*i+1konumundan başlayan sol alt ağaçtaki en büyük değeri bul veya o konum boşsa-1kullan.2*i+2konumundan başlayan sağ alt ağaçtaki en küçük değeri bul veya o konum boşsa100001kullan.- En büyük değer en az
tree[i]değerine eşitse veya en küçük değer en fazlatree[i]değerine eşitsefalsedöndür. - Son düğümden sonra
truedöndür.
def isValidBST(tree):
n = len(tree)
def largest(i):
# Largest value in the subtree at index i, or -1 when that spot is empty.
if i >= n or tree[i] == -1:
return -1
return max(tree[i], largest(2 * i + 1), largest(2 * i + 2))
def smallest(i):
# Smallest value in the subtree at index i, or 100001 when that spot is empty.
if i >= n or tree[i] == -1:
return 100001
return min(tree[i], smallest(2 * i + 1), smallest(2 * i + 2))
for i in range(n):
if tree[i] == -1:
continue
# Everything on the left must be smaller, everything on the right larger.
if largest(2 * i + 1) >= tree[i] or smallest(2 * i + 2) <= tree[i]:
return False
return TrueSıralı dolaşım değerleri kesinlikle artmalıdır
Sezgi
Sıralı dolaşım önce sol alt ağacı, sonra düğümü, ardından sağ alt ağacı ziyaret eder. İkili arama ağacında bu sıralama düzenlidir: soldaki her şey daha küçüktür, dolayısıyla önce gelir; sağdaki her şey daha büyüktür, dolayısıyla sonra gelir. İlk örnek 1, 3, 6, 8, 10, 12, 15 şeklinde okunur.
Tersi de geçerlidir ve bu, bunu bir test yapan şeydir. Herhangi bir v düğümünü ele alalım. Sıralı dizide, sol alt ağacının tamamı hemen öncesinde, sağ alt ağacının tamamı ise hemen sonrasında yer alır. Dizi kesin olarak artıyorsa, v düğümünden önceki her değer daha küçük, sonraki her değer ise daha büyüktür; dolayısıyla kural v düğümünde ve aynı şekilde diğer tüm düğümlerde de geçerlidir.
Öyleyse ağacı sıralı biçimde dolaş, değerleri topla ve her birini kendinden öncekiyle karşılaştır. İkinci örnek 5, 10, 6, 15, 20 şeklinde okunur: 10 değerinden 6 değerine iniş, yanlış taraftaki düğümü ortaya çıkarır. Üçüncü örnek 7, 12, 12 şeklindedir ve tekrarlanan 12 kesinlik kontrolünü geçemez. Her düğüm bir kez ziyaret edilir; zaman karmaşıklığı O(n), listenin alan karmaşıklığı ise O(n)'dir.
Algoritma
walk(i)yaz: yer boşsa dur; değilse2*i+1konumuna git,tree[i]değerini ekle, sonra2*i+2konumuna git.- Değerleri sıralı olarak toplamak için
walk(0)çağır. 1konumundan başlayarak herkkonumu için,values[k-1] ≥ values[k]isefalsedöndür.truedöndür.
def isValidBST(tree):
n = len(tree)
values = []
def walk(i):
# Left subtree, then the node, then the right subtree.
if i >= n or tree[i] == -1:
return
walk(2 * i + 1)
values.append(tree[i])
walk(2 * i + 2)
walk(0)
# A search tree read in order gives strictly increasing values.
for k in range(1, len(values)):
if values[k - 1] >= values[k]:
return False
return TrueAğacın aşağılarına doğru izin verilen aralığı taşı
Sezgi
Kurala bir düğümün bakış açısından bakın. Her ata, o düğüme bir sınır koyar. Düğüm, a değerini taşıyan bir atanın sol alt ağacındaysa değeri a'dan küçük olmalıdır; sağ alt ağacındaysa a'dan büyük olmalıdır. Tüm bu sınırlar birlikte açık bir aralık oluşturur: (low, high). Düğüm, değeri bu aralığın tam olarak içinde olduğunda doğru yerdedir.
Bu aralığı aşağı inerken oluşturabilirsiniz. Kökün sınırı yoktur. v değerini taşıyan bir düğümden sol çocuğuna geçerken low korunur ve high, v olacak şekilde düşürülür; sağ çocuğuna geçerken high korunur ve low, v olacak şekilde yükseltilir. v değeri eski aralığa göre denetimi geçtiğinden, yeni sınır her zaman yerini aldığı sınırdan daha dardır.
İkinci örnekte 15, (10, no limit) aralığını alır ve bunu sol çocuğuna (10, 15) olarak aktarır. 6, 10'dan küçüktür; bu nedenle başka herhangi bir düğüme bakmadan denetim hemen başarısız olur. Değerler 0 ile 10^5 arasındadır; bu yüzden -1 ve 100001, "sınır yok" anlamına gelir.
Bekleyen düğümleri, her birinin aralığıyla birlikte bir yığında tutun. Her düğüm bir kez denetlenir; zaman karmaşıklığı O(n)'dir. Yığın, tek bir yol üzerindeki bekleyen düğümleri tutar; alan karmaşıklığı O(h)'dir. İlk bozuk aralık aramayı sonlandırır.
Algoritma
(0, -1, 100001)değerini yığına ekle: kökün indeksini ve gerçek bir sınırı olmayan açık bir aralığı.(i, low, high)değerini yığından çıkar.tree[i],lowilehigharasında kesin olarak değilsefalsedöndür.- Sol çocuk
2*i+1gerçekse, onu(low, tree[i])aralığıyla yığına ekle. - Sağ çocuk
2*i+2gerçekse, onu(tree[i], high)aralığıyla yığına ekle. - Yığın boşaldığında
truedöndür.
def isValidBST(tree):
n = len(tree)
# Each entry: a node index and the open range (low, high) its value must fall in.
# -1 and 100001 lie outside every allowed value, so they mean "no limit".
stack = [(0, -1, 100001)]
while stack:
i, low, high = stack.pop()
value = tree[i]
if not (low < value < high):
return False
left, right = 2 * i + 1, 2 * i + 2
if left < n and tree[left] != -1:
stack.append((left, low, value)) # the left side must stay below value
if right < n and tree[right] != -1:
stack.append((right, value, high)) # the right side must stay above value
return True
Tuzaklar ve uç durumlar
Yanlış yanıtların çoğu ya çok az şeyi denetler ya da doğru şeyi yanlış karşılaştırmayla denetler.
- Bir düğümü yalnızca çocuklarıyla karşılaştırmak.
[10, 5, 15, -1, -1, 6, 20]içinde her ebeveyn-çocuk çifti doğru görünür; ancak6, iki seviye yukarıdaki kökün koyduğu sınırı yine de ihlal eder. - Eşit değerlere izin vermek. Sıralama her iki tarafta da katıdır; bu nedenle
[12, 7, 12]geçerli değildir.low < v < highvevalues[k-1] < values[k]kullanın, asla≤kullanmayın. - Yalnızca ebeveynin değerini aşağıya aktarmak. Sol çocuğun her iki sınıra da ihtiyacı vardır: ebeveyninden küçük ve ebeveynin sahip olduğu alt sınırdan büyük olmalıdır. Aralığın tamamını taşıyın.
- Bir düğümün alabileceği bir değeri “sınırsız” değer olarak seçmek. Değerler
0'dan başladığından,0alt sınırı[0]örneğindeki gibi0değerini taşıyan geçerli bir düğümü reddeder. İzin verilen tüm değerlerden küçük bir değerle başlayın. - Dizinin sonunu aşarak okumak. Bir çocuğu okumadan önce
2*i+1 < tree.lengthkoşulunu denetleyin ve-1değerini çocuk yok olarak kabul edin. - Dizilerin 1'den başladığı Lua ve R'deki ofseti karıştırmak.
2*i+1hesabı için düğüm dizinlerini 0 tabanlı tutun vetree[i + 1]değerini okuyun.
Sıkça sorulan sorular4
Bir BST'yi doğrulamak için her düğümü çocuklarına göre kontrol etmek neden yeterli değildir?
Kural, alt ağaçların tamamını kapsar. Kökün sağ alt ağacının derinliklerindeki bir düğüm, çok daha büyük bir düğümün sol çocuğu olsa bile kökten büyük olmalıdır. [10, 5, 15, -1, -1, 6, 20] dizisinde 6, 15 için uygun bir sol çocuktur ancak 10'un sağında yer alır; bu nedenle ağaç bir arama ağacı değildir. Yalnızca ebeveynin değil, tüm ataların sınırlarını dikkate almalısın.
Bir ikili arama ağacını doğrulamanın zaman karmaşıklığı nedir?
Hem sıralı dolaşım denetimi hem de aralık denetimi olmak üzere standart yöntemlerin ikisi de her düğümü bir kez inceler, bu nedenle O(n) zaman alırlar. Aralık denetimi, yığın için O(h) ek alan gerektirir; burada h derinliktir. Her düğümü tüm alt ağaçlarıyla karşılaştırmak da işe yarar ancak O(n × h) maliyet getirir; bu, yol şeklindeki bir ağaçta O(n²) değerine ulaşır.
Her değeri saklamadan, sıralı dolaşma ile bir BST'yi doğrulayabilir misin?
Evet. Sıralı dolaşım denetimi yalnızca bir değeri hemen önceki değerle karşılaştırır; bu nedenle önceki değeri bir liste yerine bir değişkende tut. Ağacı özyinelemeyle veya açık bir yığınla sıralı dolaş ve bir değer önceki değerden büyük değilse hemen false döndür. Böylece ek alan kullanımı O(h) olur.
Bir ikili arama ağacı yinelenen değerler içerebilir mi?
Burada kullanılan katı tanıma göre hayır: her sol değer daha küçük ve her sağ değer daha büyük olmalıdır; dolayısıyla iki eşit değer aynı anda asla sığamaz. Bazı ders kitapları, örneğin eşit değerlerin sağ tarafta olmasına izin verir. Bu kurala göre katı karşılaştırmalardan birini ≤ olarak değiştirirsiniz; bu yüzden kontrolü yazmadan önce tanımı okuyun.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
Python
def isValidBST(tree):
# Kodu buraya yazınDurum 1
Durum 2
Durum 3
Girdi
tree = [8, 3, 12, 1, 6, 10, 15]
Beklenen
true