
こんにちは
今回の学びは
・合計の差分を持ち歩くというのと、葉の判定がポイントの問題です
問題はpath-sum
(時間配分は5分問題理解=restate&clarify 10分検討multip-sol, analysis, reasons 10分実装 20分振り返り の一文45分構成)をできればgoogle docで笑&真剣。
終始、わからないことは声にだして、明確にしていきましょう。
1,まずは入出力をしっかりおさえましょう。(問題を自分の言葉で復唱すること、わからないことをクリアにすると、前提も声にだすこと)
2,いくつかのソリューションを声にだして出してみましょう。(もちろんtime complexit, space complexityの分析や理由を付け加えて)
3,どれでいくか、一緒に決定しましょう。(理由付きでね、よろしく)
timespace analysis (時間とスペースの分析)は 〇〇です
場合によっては、pseudocode(擬似コード)をかいてみてもよい。
4、実装しましょう。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def __str__(self):
return "val:%s, left:%s, right:%s" % (self.val,
self.left.val if self.left else "none",
self.right.val if self.right else "none",
)
def bt_sum(node, k, path):
paths = []
if node:
rest = k - node.val
path_copy = path[:]
path_copy.append(node.val)
is_leaf = node.left is None and node.right is None
if is_leaf:
if rest == 0:
return [path_copy]
else:
return []
else:
paths += bt_sum(node.left, rest, path_copy)
paths += bt_sum(node.right, rest, path_copy)
return paths
root = TreeNode(10)
root.left = TreeNode(16)
root.right = TreeNode(5)
root.left.right = TreeNode(-3)
root.right.left = TreeNode(6)
root.right.right = TreeNode(11)
path = []
ans = bt_sum(root, 26, path)
print(ans)
よくする間違い!
配列(path)を引数として持たす時、参照として持ち歩くので、その影響がわかっていない
赤字でコピーするのがポイント。いっつも、ハマるので注意。このために配列をコピーして走査するのでstackの積み重ねO(logN) * O(N)のspaceが必要で非常にメモリ効率はよくない
def bt_sum(node, k, path):
paths = []
if node:
rest = k - node.val
path_copy = path[:]
path_copy.append(node.val)
is_leaf = node.left is None and node.right is None
if is_leaf:
if rest == 0:
return [path_copy]
else:
return []
else:
paths += bt_sum(node.left, rest, path_copy)
paths += bt_sum(node.right, rest, path_copy)
return paths
ちなみに、メモリ効率はテスト結果としては悪くないです。下の関数は返却値が{true|false}ですが、上の関数ではpathのリストを全て返すようにしています。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
"""
edge case: (initial acc is 0 , what if sum = 0 is given?!)
root = [1], sum = 0
edge case: ( return True only if it reaches to the end of branch)
https://leetcode.com/submissions/detail/289318789/
root = [1, 2], sum = 1
"""
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
def bt_sum(node, k, path):
paths = []
if node:
rest = k - node.val
path_copy = path[:]
path_copy.append(node.val)
is_leaf = node.left is None and node.right is None
if is_leaf:
if rest == 0:
return [path_copy]
else:
return []
else:
paths += bt_sum(node.left, rest, path_copy)
paths += bt_sum(node.right, rest, path_copy)
return paths
return len(bt_sum(root, sum, [])) > 0
def hasPathSum2(self, root: TreeNode, sum: int) -> bool:
# dfsでaccumulative sumをcarry on すればよい
def dfs_accumulate(node, goal: int, acc:int,) -> bool:
if node is None: return False
_acc = 0 if acc == None else acc
_acc_new = _acc + node.val
is_leaf = (node.left == None and node.right == None)
if _acc_new == goal and is_leaf:
return True
if node.left:
if dfs_accumulate(node.left, goal, _acc_new): return True
if node.right:
if dfs_accumulate(node.right, goal, _acc_new): return True
return False
if root is None: return False
return dfs_accumulate(root, sum, None)
5、エッジケースとサンプルテストを忘れずに!
合計の差分を持ち歩くというのと、葉の判定がポイントの問題です
振り返り
「次のこの問題を解くばあい知っていればよい一つの事実とは?」
まとめ
以上です