# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def __init__(self):
self.memo = dict()
def rob(self, root: Optional[TreeNode]) -> int:
# # 暴力搜索 + 记忆化
# if not root:
# return 0
# if self.memo.get(root):
# return self.memo[root]
# # 如果选择 root
# res1 = root.val
# if root.left:
# res1 += self.rob(root.left.left) + self.rob(root.left.right)
# if root.right:
# res1 += self.rob(root.right.left) + self.rob(root.right.right)
# # 如果不选择 root
# res2 = self.rob(root.left) + self.rob(root.right)
# res = max(res1, res2)
# self.memo[root] = res
# return res
# 动态规划
# f 表示选择节点 root 的情况下,所能获得的最大利益 f(root) = root.val + g(root.left) + g(root.right)
# g 表示不选择节点 root 的情况下,所能获得的最大利益 g(root) = max(f(root.left), g(root.left)) + max(f(root.right), g(root.right))
def DFS(root):
if not root:
return 0, 0
# 后序遍历
leftchild_steal, leftchild_nosteal = DFS(root.left)
rightchild_steal, rightchild_nosteal = DFS(root.right)
# 偷当前node,则最大收益为【投当前节点+不偷左右子树】
steal = root.val + leftchild_nosteal + rightchild_nosteal
# 不偷当前node,则可以偷左右子树
nosteal = max(leftchild_steal, leftchild_nosteal) + max(rightchild_steal, rightchild_nosteal)
return steal, nosteal
return max(DFS(root))
class Solution:
def countBits(self, n: int) -> List[int]:
# 动态规划
# 状态转移:奇数时,dp[i] = dp[i-1] + 1
# 偶数时,dp[i] = dp[i // 2]
res = [0 for _ in range(n+1)]
for i in range(1, n+1):
if i % 2 == 1:
res[i] = res[i-1] + 1
else:
res[i] = res[i//2]
return res
class Solution:
def decodeString(self, s: str) -> str:
# 辅助栈
stack, res, multi = [], "", 0
for c in s:
# 左括号时,重置 multi 和 res,multi 为要重复的次数,res 为待重复的字符串
if c == '[':
stack.append([multi, res])
res, multi = "", 0
# 右括号时,更新 res
elif c == ']':
cur_multi, last_res = stack.pop()
res = last_res + cur_multi * res
elif '0' <= c <= '9':
multi = multi * 10 + int(c)
else:
res += c
return res
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
# 按照第一个元素降序排列,再按照第二个元素升序排列
# 保证先放入 res 中的都是高个子
res = []
people = sorted(people, key = lambda x: (-x[0], x[1]))
for p in people:
if len(res) <= p[1]:
res.append(p)
else:
res.insert(p[1], p)
return res
class Solution:
def canPartition(self, nums: List[int]) -> bool:
# 动态规划
# dp[i][j]表示 nums[:i+1]数组中是否可以选出和为 j
n = len(nums)
# 特殊情况处理
if n < 2:
return False
numsSum = sum(nums)
maxNum = max(nums)
# 和为奇数,无法选择
if numsSum % 2 == 1:
return False
# 最大的数大于总和的一半,无法选择
if 2 * maxNum > numsSum:
return False
target = numsSum // 2
# dp数组和边界条件
dp = [[False]*(target+1) for _ in range(n)]
for i in range(n):
dp[i][0] = True
dp[0][nums[0]] = True
for i in range(1, n):
num = nums[i]
for j in range(1, target+1):
if j >= num:
# 可以选 num 或不选
dp[i][j] = dp[i-1][j] or dp[i-1][j-num]
else:
# 不能选 num
dp[i][j] = dp[i-1][j]
return dp[n-1][target]
# 空间可优化到一维,但需要注意从后往前更新,不然 dp[j-num]会被更新,不再是上一行的值
DFS or 前缀和
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
# DFS
# 定义 rootSum(p, target) 表示以 p 为起点,且路径和为 target 的路径个数
# 时间复杂度 O(n^2)
def rootSum(p, target):
if not p:
return 0
val = p.val
res = 0
# 这个不能直接 return,有负数
if val == target:
res += 1
res += rootSum(p.left, target-val) + rootSum(p.right, target-val)
return res
if not root:
return 0
# 以根节点为起点的个数
res = rootSum(root, targetSum)
# 左子树的个数(不一定左节点是根节点)
res += self.pathSum(root.left, targetSum)
# 右子树的个数(不一定右节点是根节点)
res += self.pathSum(root.right, targetSum)
return res
# # 前缀和
# # 保存根节点到当前节点(不包括)的前缀和,当遍历到当前节点时,根节点到当前节点(包括)和为 curr,在前缀和 map 中查找是否存在和为 curr-target 的路径,则一定存在和为 target 的路径
# prefix = collections.defaultdict(int)
# prefix[0] = 1 # 空路径需要保存,处理 curr=target 的路径
# # 返回 root 为根节点的和为 target 的路径条数,curr 为根节点到当前节点(不包括)和
# def dfs(root, curr):
# if not root:
# return 0
# ret = 0
# curr += root.val # 根节点到当前节点(包括)和
# ret += prefix[curr - targetSum] # 查找和为 curr-target 的路径个数
# prefix[curr] += 1 # 更新前缀和
# ret += dfs(root.left, curr)
# ret += dfs(root.right, curr)
# prefix[curr] -= 1 # 递归退出后需要删除,避免不是一条路径的
# return ret
# return dfs(root, 0)