本文为Python算法题集之一的代码示例
给定一个二叉树的根节点 root
,和一个整数 targetSum
,求该二叉树里节点值之和等于 targetSum
的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例 1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
示例 2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
提示:
[0,1000]
-109 <= Node.val <= 109
-1000 <= targetSum <= 1000
通常优化:减少循环层次
通常优化:增加分支,减少计算集
通常优化:采用内置算法来提升计算速度
分析题目特点,分析最优解
可以采用前缀和思路求解,两个节点之间的前缀和之差即为之间的路径和
可以采用哈希列表【字典】来进行根序列的前缀和计数,任何前缀和=当前前缀和-targetSum的,之间路径即为有效路径
可以采用默认字典结构来简化代码,并检测默认字典结构性能
CheckFuncPerf
(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块使用深度优先算法执行遍历,枚举路径和,检测后返回有效数
页面功能测试,马马虎虎,超过47%
import CheckFuncPerf as cfp
class Solution:
def pathSum_base(self, root, targetSum):
def getCount(root, uppers, targetSum):
result = 0
if not root:
return result
if root.val == targetSum:
result += 1
if uppers:
isumupper = 0
for iIdx in range(len(uppers)):
isumupper += uppers[-iIdx-1]
if isumupper+root.val == targetSum:
result += 1
uppers.append(root.val)
result += getCount(root.left, uppers, targetSum)
result += getCount(root.right, uppers, targetSum)
uppers.pop()
return result
uppers = []
return getCount(root, uppers, targetSum)
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.pathSum_base, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 pathSum_base 的运行时间为 5516.24 ms;内存使用量为 4.00 KB 执行结果 = 15557
使用深度优先算法执行遍历,检测前缀和,然后返回有效数
页面功能测试,马马虎虎,超过58%
import CheckFuncPerf as cfp
class Solution:
def pathSum_ext1(self, root, targetSum):
def getCount(root, uppers, targetSum):
result = 0
if not root:
return result
if root.val == targetSum:
result += 1
if uppers:
ipreupper = uppers[-1]
imatch = ipreupper + root.val - targetSum
if imatch == 0:
result += 1
for iIdx in range(1, len(uppers)):
if uppers[-iIdx-1] == imatch:
result += 1
uppers.append(ipreupper+root.val)
else:
uppers.append(root.val)
result += getCount(root.left, uppers, targetSum)
result += getCount(root.right, uppers, targetSum)
uppers.pop()
return result
uppers = []
return getCount(root, uppers, targetSum)
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.pathSum_ext1, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 pathSum_ext1 的运行时间为 3008.68 ms;内存使用量为 0.00 KB 执行结果 = 15557
使用深度优先算法执行遍历,将前缀和放入字典计数,检索返回有效数,效率提升了一个数量级
页面功能测试,天下无双,超越98%
import CheckFuncPerf as cfp
class Solution:
def pathSum_ext2(self, root, targetSum):
dict_preuppers = {}
dict_preuppers[0] = 1
def getCount(root, icursum, targetSum):
result = 0
if not root:
return result
icursum += root.val
result += dict_preuppers.get(icursum-targetSum, 0)
dict_preuppers[icursum] = dict_preuppers.get(icursum, 0) + 1
result += getCount(root.left, icursum, targetSum)
result += getCount(root.right, icursum, targetSum)
dict_preuppers[icursum] -= 1
return result
return getCount(root, 0, targetSum)
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.pathSum_ext2, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 pathSum_ext2 的运行时间为 546.13 ms;内存使用量为 180.00 KB 执行结果 = 15557
使用深度优先算法执行遍历,采用默认字典defaultdict
,将前缀和放入defaultdict
计数,检索返回有效数【减少字典的出错处理】
页面功能测试,性能优越,超越90%
import CheckFuncPerf as cfp
class Solution:
def pathSum_ext3(self, root, targetSum):
from collections import defaultdict
dict_preuppers = defaultdict(int)
dict_preuppers[0] = 1
def getCount(root, icursum, targetSum):
result = 0
if not root:
return result
icursum += root.val
result += dict_preuppers[icursum-targetSum]
dict_preuppers[icursum] += 1
result += getCount(root.left, icursum, targetSum)
result += getCount(root.right, icursum, targetSum)
dict_preuppers[icursum] -= 1
return result
return getCount(root, 0, targetSum)
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.pathSum_ext3, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 pathSum_ext3 的运行时间为 446.10 ms;内存使用量为 212.00 KB 执行结果 = 15557
根据本地日志分析,最优算法为第4种方式【DFS递归+默认字典】pathSum_ext3
import random
ilen, imode, itargetSum = 1000000, 1, 1024
def generate_binary_tree(node_count, imode):
if node_count <= 0:
return None
root = TreeNode(random.randint(1, 100))
node_count -= 1
if imode > 3:
imode = 1
if imode == 1:
left = generate_binary_tree(node_count // 2, imode+1)
right = generate_binary_tree(node_count // 2, imode+1)
root.left = left
root.right = right
elif imode==2:
left = generate_binary_tree(node_count, imode+1)
root.left = left
else:
right = generate_binary_tree(node_count, imode+1)
root.right = right
return root
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.pathSum_base, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.pathSum_ext1, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.pathSum_ext2, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.pathSum_ext3, aSolution, aroot, itargetSum)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 算法本地速度实测比较
函数 pathSum_base 的运行时间为 5516.24 ms;内存使用量为 4.00 KB 执行结果 = 15557
函数 pathSum_ext1 的运行时间为 3008.68 ms;内存使用量为 0.00 KB 执行结果 = 15557
函数 pathSum_ext2 的运行时间为 546.13 ms;内存使用量为 180.00 KB 执行结果 = 15557
函数 pathSum_ext3 的运行时间为 446.10 ms;内存使用量为 212.00 KB 执行结果 = 15557
一日练,一日功,一日不练十日空
may the odds be ever in your favor ~