Memvalidasi BST dan Sifat In-Order
Validasi pohon biner sebagai BST menggunakan batas minimum/maksimum yang diteruskan ke bawah pohon dan dengan memeriksa apakah traversal in-order menghasilkan urutan terurut.
Memvalidasi BST dan Sifat In-Order adalah pelajaran Coding Interview Prep gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Coding Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Masalah Validasi BST
Validasi BST (LeetCode #98) adalah masalah wawancara klasik yang menjebak banyak kandidat. Pendekatan naif hanya memeriksa bahwa nilai setiap simpul lebih besar daripada anak kirinya dan lebih kecil daripada anak kanannya, tetapi pemeriksaan lokal ini tidak memadai. Sebuah simpul dalam subpohon mungkin memenuhi aturan lokal, tetapi tetap melanggar sifat BST secara keseluruhan. Solusi yang benar meneruskan batas minimum/maksimum yang valid ke seluruh pohon.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
# Why local check fails:
# 5
# / \
# 1 4
# / \
# 3 6
# Node 4's children (3, 6) satisfy local rule,
# but 4 < 5 and is in the RIGHT subtree -- BST violated!
print('Local check is insufficient -- use min/max bounds')Pendekatan Batas Minimum/Maksimum
Teruskan batas bawah dan atas ke dalam rekursi. Pada setiap simpul, pastikan bahwa low < node.val < high. Saat melakukan rekursi ke kiri, perbarui batas atas menjadi node.val (subpohon kiri harus lebih kecil). Saat melakukan rekursi ke kanan, perbarui batas bawah menjadi node.val (subpohon kanan harus lebih besar). Mulailah dengan low = -infinity dan high = +infinity.
def is_valid_bst(root, low=float('-inf'), high=float('inf')):
if not root:
return True
if not (low < root.val < high):
return False
return (is_valid_bst(root.left, low, root.val) and
is_valid_bst(root.right, root.val, high))
# Valid BST:
valid = TreeNode(5)
valid.left = TreeNode(3)
valid.right = TreeNode(7)
print(is_valid_bst(valid)) # True
# Invalid BST (3 is in wrong subtree conceptually):
invalid = TreeNode(5)
invalid.left = TreeNode(1)
invalid.right = TreeNode(4)
invalid.right.left = TreeNode(3)
invalid.right.right = TreeNode(6)
print(is_valid_bst(invalid)) # False (4 < 5 in right subtree)Validasi dengan Penelusuran Urutan-Tengah
Pendekatan validasi alternatif menggunakan sifat terurut pada penelusuran urutan-tengah BST: kumpulkan urutan urutan-tengah dan pastikan urutan tersebut meningkat secara ketat. Cara ini elegan dan mudah dipahami. Namun, cara ini menggunakan ruang tambahan O(n) untuk menyimpan urutan tersebut. Versi yang dioptimalkan menggunakan satu penunjuk prev selama penelusuran untuk memeriksa setiap pasangan tanpa menyimpan seluruh urutan.
def is_valid_bst_inorder(root):
prev = [float('-inf')]
def inorder(node):
if not node:
return True
if not inorder(node.left):
return False
if node.val <= prev[0]: # not strictly increasing
return False
prev[0] = node.val
return inorder(node.right)
return inorder(root)
valid = TreeNode(5)
valid.left = TreeNode(3)
valid.right = TreeNode(7)
valid.left.left = TreeNode(1)
valid.left.right = TreeNode(4)
print(is_valid_bst_inorder(valid)) # True
invalid = TreeNode(5)
invalid.left = TreeNode(6) # 6 > 5 in left subtree!
print(is_valid_bst_inorder(invalid)) # FalseMembandingkan Kedua Pendekatan Validasi
Pendekatan batas minimum/maksimum memerlukan waktu O(n) dan ruang O(h) (hanya batas pada tumpukan pemanggilan). Pendekatan penunjuk sebelumnya pada urutan-tengah juga memerlukan waktu O(n) dan ruang O(h). Keduanya optimal. Pendekatan minimum/maksimum lebih umum dan tetap mudah digunakan saat diperluas ke masalah dengan batasan tambahan. Dalam wawancara, bersiaplah untuk mempresentasikan keduanya dan membahas komprominya—menunjukkan pemahaman terhadap alternatif merupakan indikasi yang kuat.
# Both approaches:
# Time: O(n) -- visit each node once
# Space: O(h) -- call stack depth
# h = O(log n) balanced, O(n) skewed
# When to choose which:
# min/max bounds:
# - Cleaner for trees with constraints beyond BST
# - No global state (purely functional)
# in-order prev:
# - More intuitive (sorted sequence check)
# - Easier to convert to iterative with a stack
print('Both O(n) time, O(h) space -- choose by clarity')Memulihkan BST: Dua Simpul yang Tertukar
Memulihkan BST (LeetCode #99) memperbaiki BST yang tepat dua simpulnya tertukar. Selama penelusuran urutan-tengah, BST yang tersusun dengan benar menghasilkan urutan terurut. Jika dua simpul tertukar, akan ada satu atau dua pelanggaran saat prev.val > current.val. Simpul pertama dari pelanggaran pertama dan simpul kedua dari pelanggaran terakhir adalah dua simpul yang salah tempat—tukarkan nilai keduanya.
def recover_tree(root):
first = second = prev = None
def inorder(node):
nonlocal first, second, prev
if not node:
return
inorder(node.left)
if prev and prev.val > node.val:
if not first:
first = prev # first violator
second = node # always update second
prev = node
inorder(node.right)
inorder(root)
# Swap values of the two misplaced nodes
if first and second:
first.val, second.val = second.val, first.val
root = TreeNode(3)
root.left = TreeNode(1)
root.right = TreeNode(4)
root.right.left = TreeNode(2) # 2 and 3 are swapped
recover_tree(root)
print(root.val, root.right.left.val) # 2, 3 (fixed)BST ke Larik Terurut dengan Urutan-Tengah
Mengonversi BST menjadi larik terurut sangat mudah: lakukan penelusuran urutan-tengah dan kumpulkan nilainya. Operasi dengan waktu O(n) dan ruang O(n) ini merupakan cara cepat untuk menerapkan algoritma larik terurut (pencarian biner, dua penunjuk) pada data BST. Operasi ini sering menjadi langkah awal dalam soal BST bertahap seperti 'gabungkan dua BST' atau 'temukan median BST'.
def bst_to_sorted_array(root):
result = []
def inorder(node):
if not node:
return
inorder(node.left)
result.append(node.val)
inorder(node.right)
inorder(root)
return result
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(6)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
root.right.left = TreeNode(5)
root.right.right = TreeNode(7)
print(bst_to_sorted_array(root)) # [1, 2, 3, 4, 5, 6, 7]Menggabungkan Dua BST
Untuk menggabungkan dua BST menjadi satu larik terurut, konversikan masing-masing BST menjadi larik terurut dalam waktu O(n) dan O(m), lalu gabungkan kedua larik terurut menggunakan tahap penggabungan dari pengurutan gabung dalam waktu O(n+m). Total waktu: O(n+m). Jika hasilnya perlu berupa BST yang seimbang, masukkan larik terurut hasil penggabungan ke algoritma larik-terurut-ke-BST. Penguraian menjadi submasalah sederhana seperti ini merupakan ciri solusi yang jelas dan mudah dipahami pewawancara.
def merge_two_bsts(root1, root2):
def inorder(node, arr):
if not node:
return
inorder(node.left, arr)
arr.append(node.val)
inorder(node.right, arr)
arr1, arr2 = [], []
inorder(root1, arr1)
inorder(root2, arr2)
# Merge two sorted arrays
merged = []
i = j = 0
while i < len(arr1) and j < len(arr2):
if arr1[i] <= arr2[j]:
merged.append(arr1[i]); i += 1
else:
merged.append(arr2[j]); j += 1
merged.extend(arr1[i:])
merged.extend(arr2[j:])
return merged
r1 = TreeNode(2); r1.left = TreeNode(1); r1.right = TreeNode(4)
r2 = TreeNode(3); r2.left = TreeNode(0); r2.right = TreeNode(5)
print(merge_two_bsts(r1, r2)) # [0, 1, 2, 3, 4, 5]Menghitung Simpul dalam Rentang BST
Hitung jumlah simpul yang nilainya berada dalam rentang [low, high]. Pemindaian urutan-tengah secara menyeluruh memerlukan O(n). Versi yang memanfaatkan BST melakukan pemangkasan: jika nilai simpul saat ini lebih kecil daripada low, tidak ada gunanya memeriksa subpohon kiri (semua nilai di sana juga lebih kecil daripada low). Demikian pula, pangkas subpohon kanan ketika nilai saat ini lebih besar daripada high. Kasus rata-ratanya adalah O(log n + k), dengan k sebagai jumlah simpul yang cocok.
def range_sum_bst(root, low, high):
if not root:
return 0
total = 0
if low <= root.val <= high:
total += root.val
if root.val > low: # left subtree may have values >= low
total += range_sum_bst(root.left, low, high)
if root.val < high: # right subtree may have values <= high
total += range_sum_bst(root.right, low, high)
return total
root = TreeNode(10)
root.left = TreeNode(5)
root.right = TreeNode(15)
root.left.left = TreeNode(3)
root.left.right = TreeNode(7)
root.right.right = TreeNode(18)
print(range_sum_bst(root, 7, 15)) # 7 + 10 + 15 = 32Nilai Duplikat dan BST Ketat vs Tidak Ketat
Invarian BST standar menggunakan ketidaksamaan ketat: nilai subpohon kiri harus lebih kecil secara ketat dan nilai subpohon kanan harus lebih besar secara ketat. Beberapa soal mengizinkan duplikat, dengan menempatkannya di subpohon kiri (kiri <= akar) atau subpohon kanan (akar < kanan). Saat memvalidasi BST, selalu periksa definisi yang digunakan dalam pernyataan soal. Pendekatan batas minimum/maksimum menangani kedua variasi dengan menyesuaikan apakah pemeriksaan batas harus ketat atau inklusif.
# Strict BST (LeetCode default): left < root < right
def is_valid_strict(root, lo=float('-inf'), hi=float('inf')):
if not root:
return True
if not (lo < root.val < hi): # STRICT inequalities
return False
return (is_valid_strict(root.left, lo, root.val) and
is_valid_strict(root.right, root.val, hi))
# Non-strict BST (allows duplicates in right): left <= root < right
def is_valid_nonstrict(root, lo=float('-inf'), hi=float('inf')):
if not root:
return True
if not (lo <= root.val < hi): # NOTE: <= for left side
return False
return (is_valid_nonstrict(root.left, lo, root.val + 1) and
is_valid_nonstrict(root.right, root.val, hi))
print('Always clarify strict vs non-strict with interviewer')Urutan-Tengah sebagai Alat BST Serbaguna
Penelusuran urutan-tengah adalah alat serbaguna untuk soal BST. Setiap kali soal BST menanyakan urutan terurut, elemen ke-k, kueri rentang, atau sifat urutan, pertimbangkan apakah pemindaian urutan-tengah (atau versi terbaliknya) dapat memberikan jawabannya. Sebagian besar soal khusus BST dapat diringkas menjadi: telusuri dalam urutan terurut dan lakukan sesuatu pada setiap langkah. Mengenali pemetaan ini dengan cepat merupakan keterampilan penting dalam wawancara.
# Problems solved elegantly with in-order:
# 1. Validate BST: check prev <= curr during in-order
# 2. Kth smallest: count k steps in in-order
# 3. Kth largest: count k steps in REVERSE in-order
# 4. Closest value to target: find crossover in in-order
# 5. BST to sorted array: collect in-order into list
# 6. Recover BST: find 1-2 violations in in-order
# 7. Sum of range [lo, hi]: accumulate during in-order
# The key insight: in-order visits BST nodes in sorted order.
# All sorted-order reasoning translates to in-order DFS.
print('In-order = sorted access = foundation of BST reasoning')Nilai Terdekat dalam BST
Temukan simpul yang nilainya paling dekat dengan suatu sasaran. Manfaatkan pengurutan BST: mulai dari akar, lacak nilai terdekat yang telah ditemukan, lalu bergerak menuju sasaran (ke kiri jika sasaran lebih kecil, ke kanan jika lebih besar). Pendekatan O(h) ini lebih efisien daripada pemindaian urutan-tengah dan menunjukkan pemanfaatan efektif sifat BST untuk memangkas ruang pencarian.
def closest_value(root, target):
closest = root.val
curr = root
while curr:
if abs(curr.val - target) < abs(closest - target):
closest = curr.val
if target < curr.val:
curr = curr.left
elif target > curr.val:
curr = curr.right
else:
break # exact match
return closest
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(5)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
print(closest_value(root, 3.714286)) # 4Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pengodean dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini, Anda mempelajari: validasi BST dengan batas minimum/maksimum (menghindari jebakan pemeriksaan lokal), alternatif penunjuk sebelumnya pada urutan-tengah untuk validasi, serta urutan-tengah sebagai alat BST universal untuk jumlah rentang, nilai terdekat, dan operasi penggabungan. Berikutnya, kita menggunakan sifat urutan-tengah BST untuk menemukan elemen terkecil ke-k.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Memvalidasi BST dan Sifat In-Order” gratis?
Ya — teks lengkap “Memvalidasi BST dan Sifat In-Order” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Coding Interview Prep, upgrade ke CoddyKit PRO. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Memvalidasi BST dan Sifat In-Order”?
Validasi pohon biner sebagai BST menggunakan batas minimum/maksimum yang diteruskan ke bawah pohon dan dengan memeriksa apakah traversal in-order menghasilkan urutan terurut. Kamu berlatih Coding Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Coding Interview Prep?
Tidak diperlukan pengalaman sebelumnya. Coding Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Memvalidasi BST dan Sifat In-Order” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Coding Interview Prep ini?
Ya. Setiap pelajaran Coding Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Penyisipan dan Pencarian BST
- Penghapusan BST: Tiga Kasus
- Memvalidasi BST dan Sifat In-Order
- Elemen ke-K Terkecil, Jumlah Rentang, dan BST menjadi Array Terurut