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

Pythonで二分木における最も頻出する部分木の合計を求めるプログラム

問題の概要

二分木が与えられたとき、最も頻繁に出現する「部分木の合計値」を求めることを考えます。ここでいうノードの部分木合計とは、そのノード自身を含め、ノードより下にあるすべての値を足し合わせたものです。

たとえば、次のような入力が与えられたとします。

Pythonで二分木における最も頻出する部分木の合計を求めるプログラム

この場合、出力は「3」になります。なぜなら、3は2回出現するからです。1回目は左の葉ノードの値として、もう1回は木全体の合計値 3 + 6 + (-6) = 3 として現れるためです。

解決のアプローチ

この問題を解くには、次の手順に従います。

  • count := 空のマップ(辞書)を作成する
  • 関数 getSum() を定義する。この関数はノードを引数として受け取る
  • node が null の場合は 0 を返す
  • mySum := getSum(ノードの左の子) + getSum(ノードの右の子) + ノードの値
  • count[mySum] のカウントを1つ増やす
  • mySum を返す
  • メイン処理から getSum(root) を呼び出す

実装例

それでは、理解を深めるために実際のコードを見てみましょう。

from collections import defaultdict
class TreeNode:
    def __init__(self, data, left = None, right = None):
        self.val = data
        self.left = left
        self.right = right
class Solution:
    def solve(self, root):
        count = defaultdict(int)
        def getSum(node):
            if not node:
                return 0
            mySum = getSum(node.left) + getSum(node.right) + node.val
            count[mySum] += 1
            return mySum
        getSum(root)
        return max(count, key=count.get)
ob = Solution()
root = TreeNode(-6)
root.left = TreeNode(3)
root.right = TreeNode(6)
print(ob.solve(root))

入力

root = TreeNode(-6)
root.left = TreeNode(3)
root.right = TreeNode(6)

出力

3

コードの解説

このコードでは、再帰的に各ノードの部分木合計を計算しています。getSum() 関数は、左右の子ノードの合計に自分自身の値を加えた結果を返しながら、その合計値の出現回数を defaultdict を使って記録していきます。最後に max(count, key=count.get) を呼び出すことで、出現回数が最も多い合計値を取得できます。

計算量について見てみると、木のすべてのノードを一度ずつ訪問するため時間計算量は O(n)、出現回数を記録するための辞書もノード数に依存するため、必要な記憶域も O(n) となります。

  1. Pythonで二分木のルートからリーフへのパスの最大合計を求めるプログラム

    問題概要 二分木(バイナリツリー)が与えられたとき、ルートノードからリーフノードへ至る任意のパスの中で、合計値が最大となるものを求める必要があります。 例として、次のような二分木が入力された場合を考えてみましょう。 この場合の出力は 29 になります。ルートから「5 → 9 → 7 → 8」というパスを辿ったときの合計が 29 となるためです。 解法のアプローチ この問題は、深さ優先探索(DFS)を用いて、ルートから各リーフまでのすべてのパスを再帰的に走査することで解けます。具体的な手順は以下のとおりです。 walk() 関数を定義します。引数として現在のノード node と、そこまでの

  2. Pythonで解く二分木の最大パス和(Maximum Path Sum)

    問題の概要空でない二分木が1つ与えられます。この木における「最大パス和」を求めるのが目的です。ここでいうパスとは、あるノードを起点として、親子関係で結ばれたノードをたどり任意のノードへ至るまでのノード列のことです。パスには少なくとも1つのノードが含まれている必要がありますが、必ずしも根(ルート)ノードを通る必要はありません。例として、次のような二分木が入力された場合を考えてみましょう。この場合の出力は 32 となります。アルゴリズムの考え方各ノードを「パスの折り返し地点」として捉えるのがポイントです。あるノードを頂点とするパスの和は、「左部分木からの最大寄与 + 右部分木からの最大寄与 + そ