リリース・改善中
木構造とヒープ ガイド · 5/6
この章は現在、英語でのみ提供しています。
Tree and heap questions are staples of coding interviews and online assessments. The four problems below each cover one classic pattern: traversal by level, using the BST property, a size-limited heap, and merging with a heap. Think about an approach first, then compare with the solution. All the code shares this Node definition.
class Node:
def __init__(self, key, left=None, right=None):
self.key, self.left, self.right = key, left, rightGiven a binary tree, return a list with the largest key at each depth, from the root downward. An empty tree gives an empty list. For example, with root 4, children 9 and 2, and grandchildren 3, 5 and 7, the answer is [4, 9, 7].
Approach: grouping by depth points to a level-order traversal. Popping exactly "the current queue length" items at a time processes one level per round. Time is O(n); space is the size of the widest level.
from collections import deque
def level_maxima(root):
if root is None:
return []
result, queue = [], deque([root])
while queue:
best = None
for _ in range(len(queue)): # only this level's nodes
node = queue.popleft()
best = node.key if best is None else max(best, node.key)
queue.extend(c for c in (node.left, node.right) if c)
result.append(best)
return result
tree = Node(4, Node(9, Node(3), Node(5)), Node(2, None, Node(7)))
print(level_maxima(tree)) # [4, 9, 7]Given a binary search tree and two integers lo and hi, return the sum of all keys with lo <= key <= hi. Subtrees that are certainly out of range must not be visited.
Approach: prune with the BST property. If the current key is below lo, everything in its left subtree is smaller still, so skip it; if it is above hi, skip the right subtree. The number of visited nodes is roughly O(h + number of matching nodes). An explicit stack keeps deep trees safe.
def range_sum(root, lo, hi):
total, stack = 0, [root]
while stack:
node = stack.pop()
if node is None:
continue
if lo <= node.key <= hi:
total += node.key
if node.key > lo: # the left side may still hold keys >= lo
stack.append(node.left)
if node.key < hi: # the right side may still hold keys <= hi
stack.append(node.right)
return total
bst = Node(10, Node(5, Node(3), Node(7)), Node(15, None, Node(18)))
print(range_sum(bst, 6, 15)) # 7 + 10 + 15 = 32A game server receives scores one at a time. After each score, output the K-th highest score seen so far, or while fewer than K scores have arrived.
NoneApproach: keep a min-heap capped at K items. It holds only the top K scores, so its root is exactly the K-th highest. When a new score beats the root, replace the root (heapq.heapreplace or heappushpop). Each score costs O(log K) and memory is O(K), far cheaper than sorting everything.
import heapq
def kth_highest_stream(scores, k):
heap, out = [], []
for s in scores:
if len(heap) < k:
heapq.heappush(heap, s)
elif s > heap[0]:
heapq.heapreplace(heap, s) # pop the root, push s
out.append(heap[0] if len(heap) == k else None)
return out
print(kth_highest_stream([40, 10, 70, 20, 90, 50], 3))
# [None, None, 10, 20, 40, 50]Each of k servers has a list of (timestamp, message) entries sorted by time. Merge them into one time-ordered list. When timestamps tie, the server with the smaller index goes first.
Approach: keep only the next candidate from each list in a heap. Each time you pop the earliest entry, push the next entry from the same list. Storing (timestamp, server index, position) breaks ties by server index and never compares messages. With N entries in total this is O(N log k). The standard heapq.merge works the same way.
import heapq
def merge_logs(logs):
heap = [(lst[0][0], i, 0) for i, lst in enumerate(logs) if lst]
heapq.heapify(heap)
merged = []
while heap:
t, i, j = heapq.heappop(heap)
merged.append(logs[i][j])
if j + 1 < len(logs[i]):
heapq.heappush(heap, (logs[i][j + 1][0], i, j + 1))
return merged
logs = [
[(1, "a:start"), (5, "a:done")],
[(2, "b:start"), (5, "b:retry"), (9, "b:done")],
[],
[(3, "d:start")],
]
print([m for _, m in merge_logs(logs)])
# ['a:start', 'b:start', 'd:start', 'a:done', 'b:retry', 'b:done']Level-based questions call for level-order traversal, range questions for BST pruning, "top K" for a min-heap of size K, and merging sorted inputs for a heap holding the head of each input. With these four templates you can handle most variations on sight.
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。