二分木問題の解法と実装

二分木の基礎理論

二分木は各ノードの子ノード数が最大2の木構造です。主要な形態として完全二分木と完全二分木が存在します。データ格納方式には配列を用いた順序格納とポインタを用いたリンク方式があります。走査方法は以下の通りです:

  • 先行走査(深さ優先)
  • 中間走査(深さ優先)
  • 後行走査(深さ優先)
  • 階層走査(幅優先)
class BinaryNode:
    def __init__(self, value, left_child=None, right_child=None):
        self.value = value
        self.left = left_child
        self.right = right_child

再帰的走査実装

先行順走査

def preorder(node):
    if not node:
        return []
    return [node.value] + preorder(node.left) + preorder(node.right)

中間順走査

def inorder(node):
    if not node:
        return []
    return inorder(node.left) + [node.value] + inorder(node.right)

後行順走査

def postorder(node):
    if not node:
        return []
    return postorder(node.left) + postorder(node.right) + [node.value]

反復的走査実装

先行順(スタック方式)

def preorder_iterative(root):
    if not root:
        return []
    stack = [root]
    result = []
    while stack:
        current = stack.pop()
        result.append(current.value)
        if current.right:
            stack.append(current.right)
        if current.left:
            stack.append(current.left)
    return result

中間順(ポインタ追跡)

def inorder_iterative(root):
    stack = []
    output = []
    current = root
    while current or stack:
        if current:
            stack.append(current)
            current = current.left
        else:
            current = stack.pop()
            output.append(current.value)
            current = current.right
    return output

後行順(逆順出力)

def postorder_iterative(root):
    if not root:
        return []
    stack = [root]
    result = []
    while stack:
        node = stack.pop()
        result.append(node.value)
        if node.left:
            stack.append(node.left)
        if node.right:
            stack.append(node.right)
    return result[::-1]

階層走査(キュー利用)

from collections import deque

def level_order(root):
    if not root:
        return []
    output = []
    nodes_queue = deque([root])
    while nodes_queue:
        level_values = []
        for _ in range(len(nodes_queue)):
            current = nodes_queue.popleft()
            level_values.append(current.value)
            if current.left:
                nodes_queue.append(current.left)
            if current.right:
                nodes_queue.append(current.right)
        output.append(level_values)
    return output

深さと高さの計算

ノードの深さは根からの距離、高さは葉からの距離です。最大深さ計算:

def max_depth(node):
    if not node:
        return 0
    return 1 + max(max_depth(node.left), max_depth(node.right))

最小深さ計算:

def min_depth(node):
    if not node:
        return 0
    left_min = min_depth(node.left)
    right_min = min_depth(node.right)
    if not node.left or not node.right:
        return 1 + max(left_min, right_min)
    return 1 + min(left_min, right_min)

特殊二分木の操作

平衡二分木判定

def is_balanced(root):
    def check_height(node):
        if not node:
            return 0
        left_height = check_height(node.left)
        right_height = check_height(node.right)
        if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1:
            return -1
        return 1 + max(left_height, right_height)
    return check_height(root) != -1

二分探索木検証

def is_valid_bst(root):
    stack = []
    current = root
    prev_value = float('-inf')
    while current or stack:
        if current:
            stack.append(current)
            current = current.left
        else:
            current = stack.pop()
            if current.value <= prev_value:
                return False
            prev_value = current.value
            current = current.right
    return True

ノード削除処理

def delete_node(root, key):
    if not root:
        return None
    if key < root.value:
        root.left = delete_node(root.left, key)
    elif key > root.value:
        root.right = delete_node(root.right, key)
    else:
        if not root.left:
            return root.right
        if not root.right:
            return root.left
        successor = root.right
        while successor.left:
            successor = successor.left
        root.value = successor.value
        root.right = delete_node(root.right, successor.value)
    return root

構築と変換手法

配列から平衡二分探索木構築

def sorted_array_to_bst(nums):
    if not nums:
        return None
    mid_index = len(nums) // 2
    node = BinaryNode(nums[mid_index])
    node.left = sorted_array_to_bst(nums[:mid_index])
    node.right = sorted_array_to_bst(nums[mid_index+1:])
    return node

累積木への変換

def convert_bst(root):
    total = 0
    def traverse(node):
        nonlocal total
        if node:
            traverse(node.right)
            total += node.value
            node.value = total
            traverse(node.left)
    traverse(root)
    return root

タグ: 二分木 LeetCode Python アルゴリズム データ構造

5月28日 10:53 投稿