Leetcode上的递归一共有45道,现在刷了一半了,花一天半时间复盘,之后进入下一类题型。
实质
把问题转化为规模缩小了的同类问题的子问题,是一种直接或者间接调用自身的算法。
特点
- 必须有一个明确的递归结束条件,称为递归出口
- 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。(比如在leetcode上用递归求斐波那契数列就溢出)
- 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序
- 原理就是一个栈
- 好处是:写代码迅速,代码简洁,坏处是:效率低
适合题型
树、二叉树(二叉平衡树、二叉搜索树、满二叉树、普通二叉树)、链表、斐波那契、阶乘
答题模板
思考以下三个问题:
(1) 找终止条件
(2) 找返回值
(3) 本级递归应该做什么。不要考虑过多,只关心本级干什么
这个答题模板参考自三道题套路解决递归问题, 在leetcode的评论区上发现的宝藏,起初我做递归题思路是一团乱麻,看了这个博主的文章受益良多。
可能会用到的技巧
- 高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1 。
- 一颗平衡二叉树的左右子树为平衡二叉树’
- 二叉搜索树的中序遍历刚好是升序
Leetcode按照类型分组
注意,这些题有些出自深度优先遍历的分组里,要牢记DFS和递归的关系:
DFS可以用递归实现,也可以不用递归实现。
1.二叉树
110. 平衡二叉树
题目描述
给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1 。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
//深度优先遍历求树高,再根据平衡二叉树的定义判断是否平衡
/*
递归停止条件:节点为空;树不平衡
返回什么:真假
本级干什么:判左右子树高度相差值<=1 ,判左右子树是否是平衡树
*/
class Solution {
public:
bool isBalanced(TreeNode* root) {
//左右子树均是平衡二叉树
if(root==nullptr)
return true;
if(abs(depth(root->left)-depth(root->right))>1){
return false;
}
return isBalanced(root->left) && isBalanced(root->right);
}
int depth(TreeNode* root)
{
if(root==nullptr){
return 0;
}
return max(depth(root->left),depth(root->right))+1;
}
};
111. 二叉树的最小深度
题目描述
给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明:叶子节点是指没有子节点的节点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
/*思路:
终止条件:走到空节点
返回什么:返回左右子树上的最小深度+1
本级递归应该做什么:求左右子树上的最小深度
*/
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
int left=minDepth(root->left);
int right=minDepth(root->right);
if(left==0){ //应对只有右子树的情况
return right+1;
}
if(right==0){ //应对只有左子树的情况
return left+1;
}
return min(right,left)+1;
}
};
226. 翻转二叉树
翻转一棵二叉树。
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
/*
递归终止条件:root为空
返回什么:已经翻转完左右子树的根节点
本级递归做什么: 进行左右子树的翻转,左右子树的根节点的交换
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==nullptr) return root;
root->left=invertTree(root->left);
root->right=invertTree(root->right);
TreeNode* temp=root->right;
root->right=root->left;
root->left=temp;
return root;
}
};
617. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
/*
递归停止条件:root1和root2有一个为空
返回什么:返回合并后的树的根节点
本级递归应该做什么: 合并两个二叉树:
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(!root1) return root2;
if(!root2) return root1;