Python
 Computer >> コンピューター >  >> プログラミング >> Python

【Python】連結リストをジグザグ二分木に変換するプログラムの書き方

問題の概要

単方向連結リスト(片方向リンクリスト)が与えられたとき、次のルールに従って二分木へ変換することを考えます。

  • 連結リストの先頭ノード(head)が、二分木のルートになります。
  • それ以降の各ノードは、その値が親ノードより小さい場合は左の子に、そうでない場合は右の子になります。

たとえば、入力が [2,1,3,4,0,5] の場合、変換後の二分木は次のような「ジグザグ」形状になります。

【Python】連結リストをジグザグ二分木に変換するプログラムの書き方

解き方の手順

この問題は、再帰的に呼び出す関数 solve() を定義すると、シンプルに解くことができます。具体的な手順は以下の通りです。

  1. ノードを引数として受け取る関数 solve() を定義します。
  2. ノードが null(None)の場合は、None を返します。
  3. 受け取ったノードと同じ値を持つ新しいツリーノードを作成し、これを root とします。
  4. ノードの次の要素(next)が存在する場合は、値の大小によって処理を分けます。
    • next の値が現在のノードの値より小さい場合:root.left = solve(node.next) として左側に接続
    • それ以外の場合:root.right = solve(node.next) として右側に接続
  5. 最後に root を返します。

Pythonでの実装例

それでは、実際のコードを見てみましょう。

class ListNode:
    def __init__(self, data, next=None):
        self.val = data
        self.next = next

def make_list(elements):
    head = ListNode(elements[0])
    for element in elements[1:]:
        ptr = head
        while ptr.next:
            ptr = ptr.next
        ptr.next = ListNode(element)
    return head

class TreeNode:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

def print_tree(root):
    if root is not None:
        print_tree(root.left)
        print(root.data, end=', ')
        print_tree(root.right)

class Solution:
    def solve(self, node):
        if not node:
            return None
        root = TreeNode(node.val)
        if node.next:
            if node.next.val < node.val:
                root.left = self.solve(node.next)
            else:
                root.right = self.solve(node.next)
        return root

ob = Solution()
L = make_list([2,1,3,4,0,5])
print_tree(ob.solve(L))

入力

[2,1,3,4,0,5]

出力

1, 3, 0, 5, 4, 2,

コードの解説と計算量

print_tree() は二分木を中順走査(In-order Traversal)で出力する関数です。「左の子 → 自分自身 → 右の子」の順に訪問するため、上記の出力では木の構造がそのまま反映されています。今回の入力では 2 → 1 → 3 → 4 → 0 → 5 の順にノードが並んでおり、値の大小比較によってすべてのノードが一方向に連なるジグザグ状の木が構築されます。

計算量については、連結リストの各ノードを一度ずつ処理するため、時間計算量は O(n) です。また、再帰呼び出しの深さがノード数に比例するため、空間計算量も再帰スタック分の O(n) となります。

  1. Pythonで方向リストを使って二分木を走査するプログラム

    二分木と、R(右)、L(左)、U(上)からなる文字列のリスト moves が与えられているとします。ルートから出発し、moves の各指示に従って木をたどります。R は右の子ノードへ移動、L は左の子ノードへ移動、U は親ノードへ戻ることを意味します。例えば、次のような二分木があったとします。入力が [R, R, U, L] の場合、出力は 3 になります。解決のアプローチこの問題は、通過したノードの履歴をスタック(リスト)で管理することで解決できます。手順は以下の通りです。空のリスト past を用意します。moves 内の各移動指示に対して、以下を繰り返します。まず現在のノードを past

  2. Pythonで二分探索木のノードの兄弟の値を見つけるプログラム

    問題概要 値 k と二分探索木が与えられます。この木では、各ノードは葉ノードであるか、必ず2つの子を持っています。値 k を持つノードを見つけ、その兄弟ノードの値を返す必要があります。 例えば、次のような二分探索木が与えられたとします。 k = 4 の場合、出力は 10 になります(4の兄弟ノードが10だからです)。 解法のアプローチ この問題は、二分探索木の性質(左の子 < 親 < 右の子)を利用することで効率的に解けます。手順は以下の通りです。 関数 util() を定義します。引数として root(現在のノード)、k(探す値)、ans(結果を格納するリスト)を受け取りま