前言
视频观看更得劲:【小小福讲算法】硅谷工程师十五分钟带你深入理解 Recursion (递归)算法,及其衍生出的算法(分治算法 Divide and Conquer, 回溯 Ba_哔哩哔哩_bilibili
“Recursion is an approach to solving problems using a function that calls itself as a subroutine.” ---- LeetCode
为什么 function 需要 call 自己?
递归函数由终止条件(Base)和递归关系(Recursion Relation)组成
在二叉搜索树中搜索某一结点
算法步骤可以抽象为:
如果递归问题会产生重复的子问题,那么可以使用 cache 记住子问题的答案,避免重复计算。
Divide and Conquer 分而治之,几乎等同于标准的 Recursion,唯一的区别是,最后需要将子问题的结果进行合并!
- 验证二叉查找树:98. 验证二叉搜索树 - 力扣(LeetCode)
- 统计二叉树中具有双结点的结点个数获取二叉树所有双分支结点个数1
分治算法的核心是寻找子问题的解 ,解题步骤遵循「三步走」:
找出所有由 n 个 1 左右括号组成的有效的表达式:22. 括号生成 - 力扣(LeetCode)
具体的思路可以通过观看视频理解:【小小福讲算法】硅谷工程师十五分钟带你深入理解 Recursion (递归)算法,及其衍生出的算法(分治算法 Divide and Conquer, 回溯 Ba_哔哩哔哩_bilibili
可以参考这篇文章:回溯法套路模板 刷通 leetcode - 知乎 (zhihu.com)
设计思路
套路模板
res = [] # 定义全局变量保存最终结果
state = [] # 定义状态变量保存当前状态
p,q,r # 定义条件变量(一般条件变量就是题目直接给的参数)
def back(状态,条件1,条件2,……):
if # 不满足合法条件(可以说是剪枝)
return
elif # 状态满足最终要求
res.append(state) # 加入结果
return
# 主要递归过程,一般是带有 循环体 或者 条件体
for # 满足执行条件
if # 满足执行条件
back(状态,条件1,条件2,……)
back(状态,条件1,条件2,……)
return res
使用回溯法的明显标志
第一、 明确递归函数的作用和参数的含义,然后坚定的相信它的作用
第二、找到递归基
n == 0
的时候之类的情况。第三、明确递归函数返回后,该做点啥
就是将问题拆分成两个部分, 即 1
与 剩余整体
,其中 剩余整体
又可以用 1
与 剩余整体
的思想来考虑.如此思考,那么 剩余整体
完全可以用递归的方法去解决.
重中之重的点如下
联系到第一点技巧的提示,即相信剩余整体已经处理完毕之后如何与 1 的部分衔接问题.
假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一棵给定二叉树的所有双分支结点个数。
/**
* 统计二叉树的所有双分支结点个数。
*
* @param root 根节点
* @return 二叉树的所有双分支结点个数
*/
public int numberOfFullTreeNode(TreeNode root) {
int count = 0;
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
while (size-- > 0) {
TreeNode poll = queue.poll();
assert poll != null;
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
if (poll.left != null && poll.right != null) {
count++;
}
}
}
return -1;
}
需要重点去理解
public int numberOfFullTreeNode(TreeNode root){
if(root!=null){
if(root.left!=null&&root.right!=null){
//双分支结点
return numberOfFullTreeNode(root.left)+numberOfFullTreeNode(root.right)+1;
}else{
return numberOfFullTreeNode(root.left)+numberOfFullTreeNode(root.right);
}
}
}
↩︎
给你二叉树的根节点root
,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。
这个题目其实就是考察BFS求最短路径问题,🤣写这篇文章的时候还不会这招。见谅啦
下列代码可优化
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List> levelOrder(TreeNode root) {
List> lists = new ArrayList<>();
if (root == null) {
return lists;
}
Queue treeNodeQueue = new ArrayDeque<>();
treeNodeQueue.add(root);
List sameStorey = new ArrayList<>();
while (!treeNodeQueue.isEmpty()) {
//每当队列中弹出一个元素时,就需要将弹出元素子元素(左右)进行入队操作
List temp = new ArrayList<>();
while (!treeNodeQueue.isEmpty()) {
TreeNode poll = treeNodeQueue.poll();
temp.add(poll.val);
if (poll.left != null) {
sameStorey.add(poll.left);
}
if (poll.right != null) {
sameStorey.add(poll.right);
}
}
//将子节点加入到队列中,并清空集合
treeNodeQueue.addAll(sameStorey);
sameStorey.clear();
lists.add(temp);
}
return lists;
}
}