- python小知识
- 看一下95, python中的树是怎么写的
- 好题
- 124
96 n个节点组成的不同二叉树个数
关键是递归:
如果现在我在n
那么n可以拆为:
以1为分割: 0 + n-1 (0个比1小, n-1个比1大)
以2为分割: 1 + n-2 (1个比2小, n-2个比2大)
…
以n为分割: n-1 + 0 (n-1个比n小, 0个比n大)
所以状态转移方程是:
G
(
n
)
=
G
(
0
)
∗
G
(
n
−
1
)
+
G
(
1
)
∗
(
n
−
2
)
+
.
.
.
+
G
(
n
−
1
)
∗
G
(
0
)
G(n)=G(0)∗G(n−1)+G(1)∗(n−2)+...+G(n−1)∗G(0)
G(n)=G(0)∗G(n−1)+G(1)∗(n−2)+...+G(n−1)∗G(0)
这也称为卡特兰数
95 是96的升级, 不是返回个数而是所有的二叉树
class Solution:
def generateTrees(self, n: int) -> List[TreeNode]:
def generateTrees(start, end):
if start > end:
return [None,]
allTrees = []
for i in range(start, end + 1): # 枚举可行根节点
# 获得所有可行的左子树集合
leftTrees = generateTrees(start, i - 1)
# 获得所有可行的右子树集合
rightTrees = generateTrees(i + 1, end)
# 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for l in leftTrees:
for r in rightTrees:
currTree = TreeNode(i)
currTree.left = l
currTree.right = r
allTrees.append(currTree)
return allTrees
return generateTrees(1, n) if n else []
一个关键的问题, 为什么start > end时返回的是[None]
124 可以从任何地方开始的路径之和最大
这道题虽然是二叉树, 但可以从二叉树的任意一个地方开始, 就把问题变得很难了
我的第一想法是: 按照他的思路就输了(不能够这样想: 从任意一个节点出发), 原因是题所给的数据结构不支持node.parent, 往上遍历是非常困难的. 我们仍然应该保持从上到下遍历的习惯.
此时我已经有一点初步idea:
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
self.ans = -float('inf')
def score(node):
if node == None:
return 0
else:
l = score(node.left)
r = score(node.right)
L = l + node.val
R = r + node.val
A = l + r + node.val
best = max(L, R, A)
self.ans = max(self.ans, best)
return best
score(root)
return self.ans
但是这个方法在[2, -1, -2]的情况下不对, 原来对于node, 我们不仅可以左, 右, 左加右, 还能只保留自己
改为best = max(L, R, A, node.val)后结果还有一些case过不了
结果错误在于:
你原来的代码主要问题是在返回值时包含了 A(跨越左右子树的路径),这可能导致在更高层的节点计算时使用了一个已经"拐弯"的路径,违反了路径的定义(路径被定义为从树中任意节点出发,达到任意节点的序列,且路径每到达一个节点,只能选择向上或者向下访问一个相邻节点,不能重复访问)。
应该是
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
self.ans = float('-inf')
def score(node):
if node == None:
return 0
else:
l = score(node.left)
r = score(node.right)
L = l + node.val
R = r + node.val
A = l + r + node.val
self.ans = max(self.ans, L, R, A, node.val)
return max(L, R, node.val) # 只返回单边最大路径
score(root)
return self.ans
337 二叉树中的打家劫舍
第一次直接写出
class Solution:
def rob(self, root: Optional[TreeNode]) -> int:
def money(node, steal):
if node == None:
return 0
if steal:
return node.val + money(node.left, False) + money(node.right, False)
else:
l_steal = money(node.left, True)
l_not_steal = money(node.left, False)
r_steal = money(node.right, True)
r_not_steal = money(node.right,False)
return max(l_not_steal, l_steal) + max(r_not_steal, r_steal)
return max(money(root,False), money(root, True))
但很不幸的是最后两个cases超时了
用memoization来优化一下:
class Solution:
def rob(self, root: Optional[TreeNode]) -> int:
memo = {}
def money(node):
if node is None:
return (0, 0)
if node in memo:
return memo[node]
left = money(node.left)
right = money(node.right)
# 如果当前节点被偷,则不能偷左右子节点
rob = node.val + left[1] + right[1]
# 如果当前节点不被偷,则可以选择偷或不偷左右子节点
not_rob = max(left) + max(right)
memo[node] = (rob, not_rob)
return memo[node]
return max(money(root))
打败了45%
class Solution:
def rob(self, root: Optional[TreeNode]) -> int:
def dfs(node):
if not node:
return 0, 0
left = dfs(node.left)
right = dfs(node.right)
# 如果偷当前节点
rob = node.val + left[1] + right[1]
# 如果不偷当前节点
not_rob = max(left) + max(right)
return rob, not_rob
return max(dfs(root))
这样更简单一点