题目1
【简单】路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true
, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2
。
解答
有两种思想:递归与循环.
递归:参照递归的4个步骤:1.确定函数功能;2.递推公式,重要,只要把想出来了,就成功了一半;3.终止条件,通过举例子方式归纳得到.4.时空复杂度. 详见代码注释
循环:方法一:可以通过两个list交替循环,这个比较通用,比如计算树深度,打印树等任务.
方法二:通过一个stack的pop操作来实现循环.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 函数功能:输入一个root/sum,判断是否存在
# 递推公式:hasPathSum(root,sum) = hasPathSum(root.left,sum-root.val) or hasPathSum(root.left,sum-root.val)
# 终止条件:if not root: return False;if 是叶节点 and 值等于sum,return True
# 复杂度: O(N);O(logN)
# 只遍历左子树,右子树
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
if not root.left and not root.right and root.val == sum:
return True
left = self.hasPathSum(root.left,sum-root.val)
right = self.hasPathSum(root.right,sum-root.val)
return left or right
class Solution:
# 循环.通过两个list进行交替
# def hasPathSum(self,root,sum):
# if not root:
# return False
# curLayerNode = [(root,sum)]
# while curLayerNode:
# nextLayerNode = []
# for (node,val) in curLayerNode:
# if not node.left and not node.right and node.val == val:
# return True
# if node.left:
# nextLayerNode.append((node.left,val-(node.val)))
# if node.right:
# nextLayerNode.append((node.right,val-(node.val)))
# curLayerNode = nextLayerNode
# return False
#循环.通过一个stack的pop进行交替
def hasPathSum(self,root,sum):
if not root:
return False
stack = [(root,sum)]
while stack:
node,val = stack.pop()
if not node.left and not node.right and node.val == val:
return True
if node.right:
stack.append((node.right,val-node.val))
if node.left:
stack.append((node.left,val-node.val))
return False
链接:https://leetcode-cn.com/problems/path-sum/solution/shu-de-di-gui-yu-xun-huan-de-an-li-zhi-yi-by-zhang/
题目2
【简单】二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最小深度 2.
解答
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# 递归解法
class Solution:
# 递推公式:minDepth(root) = min(self.minDepth(root的子节点), min_depth)
# 终止条件:if not root: return 0;if 没有子节点,return 1
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
children = [root.left, root.right]
# if we're at leaf node
if not any(children):
return 1
min_depth = float('inf')
for c in children:
if c:
min_depth = min(self.minDepth(c), min_depth)
return min_depth + 1
class Solution:
def minDepth(self, root: TreeNode) -> int:
# 利用栈,记录深度
if not root:
return 0
min_depth = 1
stack = [(root,min_depth)]
while stack:
node,val = stack.pop()
if not node.left and not node.right:
if min_depth == 1:
min_depth = val
else:
min_depth = min(min_depth,val)
if node.right:
stack.append((node.right,val+1))
if node.left:
stack.append((node.left,val+1))
return min_depth
题目3
【简单】最长同值路径
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。
示例 1:
输入:
5
/ \
4 5
/ \ \
1 1 5
输出:
2
示例 2:
输入:
1
/ \
4 5
/ \ \
4 4 5
输出:
2
解答
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def longestUnivaluePath(self, root: TreeNode) -> int:
self.ans = 0
def arrow_length(node):
if not node: return 0
left_length = arrow_length(node.left)
right_length = arrow_length(node.right)
left_arrow = right_arrow = 0
if node.left and node.left.val == node.val:
left_arrow = left_length + 1
if node.right and node.right.val == node.val:
right_arrow = right_length + 1
self.ans = max(self.ans, left_arrow + right_arrow)
return max(left_arrow, right_arrow)
arrow_length(root)
return self.ans
【补充】
算法题之递归调用
递归求解算法题有三个要素:(这里以n的阶乘为例)
1、函数功能
// 算 n 的阶乘(假设n不为0)
int f(int n){
/**/
}
2、终止条件
所谓递归,就是会在函数内部代码中,调用这个函数本身,所以必须要找出递归的结束条件,不然的话,会一直调用自己,进入无限循环。也就是说,需要找出当参数为啥时,递归结束,之后把结果返回。
// 算 n 的阶乘(假设n不为0)
int f(int n){
if(n <= 2){
return n;
}
}
3、递归公式
不断缩小参数的范围,例如,f(n) 这个范围比较大,我们可以让 f(n) = n * f(n-1)
// 算 n 的阶乘(假设n不为0)
int f(int n){
if(n <= 2){
return n;
}
// 把 f(n) 的等价操作写进去
return f(n-1) * n;
}
例: 斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
终止条件:
F(0) = 0, F(1) = 1
递归公式:
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
class Solution:
def fib(self, N: int) -> int:
if N == 0:
return 0
elif N == 1:
return 1
else:
return self.fib(N-1) + self.fib(N-2)
例:爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
终止条件:
F(1) = 1, F(2)=2
递归公式:
第一种跳法:第一次跳了1个台阶,那么还剩下n-1个台阶还没跳,剩下的n-1个台阶的跳法有F(N-1)种。
第二种跳法:第一次跳了2个台阶,那么还剩下n-2个台阶还没,剩下的n-2个台阶的跳法有F(N-2)种。
F(N) =F(N-1)+F(N-2)
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
elif n == 2:
return 2
else:
return self.climbStairs(n-1) + self.climbStairs(n-2)
例:反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
终止条件:
当链表只有一个节点,或者如果是空表的话,你应该知道结果吧?直接啥也不用干,直接把 head 返回
递归公式:
以下面head->1->2->3->4为例
已经定义了 reverseLis t函数的功能可以把一个单链表反转,所以,我们对 2->3->4反转之后的结果应该是这样:
把 2->3->4 递归成 4->3->2。但1 这个节点我们并没有去碰它,所以 1 的 next 节点仍然是连接这 2。
接下来只需要把节点 2 的 next 指向 1,然后把 1 的 next 指向 null,即通过改变 newList 链表之后的结果如下:
也就是说,reverseList(head) 等价于 reverseList(head.next) + 改变一下1,2两个节点的指向。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# 1.递归结束条件
if head is None or head.next is None:
return head
# 递归反转 子链表
newList = self.reverseList(head.next)
# 改变 1,2节点的指向。
# 通过 head.next获取节点2
t1 = head.next
# 让 2 的 next 指向 2
t1.next = head
# 1 的 next 指向 null
head.next = None
# 把调整之后的链表返回。
return newList
参考: