📝前言说明:
- 本专栏主要记录本人递归,搜索与回溯算法的学习以及LeetCode刷题记录,按专题划分
- 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
- 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽
你可以点击下方链接,进行该专题内不同子专题的学习
点击链接 | 开始学习 |
---|---|
导论 | 递归 (一) 、递归 (二) |
二叉树的深搜 | 穷举 vs 暴搜 vs 深搜 vs 回溯 vs 剪枝 |
综合练习(一) | 综合练习(二) |
综合练习(三) | 综合练习(四) |
FloodFill(一) | FloodFill(二) |
记忆化搜索(一) | 记忆化搜索(二) |
题单汇总链接:点击 → 题单汇总
题目
2331. 计算布尔二叉树的值
个人解
思路:
- 子问题:给一个根节点,计算这个布尔二叉树的值并返回
- 函数体:先递归得到左右布尔二叉子树的值,然后再根据根节点的val进行计算
- 函数出口:当节点为空 / 叶子节点。为空时,返回 1
屎山代码(通过):
class Solution {
public:
bool evaluateTree(TreeNode* root)
{
if(root == nullptr) return 1;
if(root->left == nullptr && root->right == nullptr) return root->val;
if(root->val == 2)
return evaluateTree(root->left) || evaluateTree(root->right);
else
return evaluateTree(root->left) && evaluateTree(root->right);
}
};
时间复杂度:O(n),每个节点都要被访问一次
空间复杂度:O(n)
129. 求根节点到叶节点数字之和
优质解
思路:
- 用前序遍历,并且把上层信息往下传,当到达递归出口以后,再层层把结果传回来
- 在前序遍历的过程中,我们可以往左右⼦树传递信息,并且在回溯时得到左右⼦树的返回值。递归函数可以帮我们完成两件事:
- 将⽗节点的数字与当前节点的信息整合到⼀起,计算出当前节点的数字,然后传递到下⼀层进⾏递归;
- 当遇到叶⼦节点的时候,就不再向下传递信息,⽽是将整合的结果向上⼀直回溯到根节点。
代码:
class Solution {
public:
int sumNumbers(TreeNode* root, int presum = 0)
{
if(root == nullptr) return 0;
presum = presum * 10 + root->val;
if(root->left == nullptr && root->right == nullptr) return presum;
return sumNumbers(root->left, presum) + sumNumbers(root->right, presum);
}
};
时间复杂度:O(n)
空间复杂度:O(n)
814. 二叉树剪枝
优质解
思路:
我们通过在决策树上分析,模拟递归展开和返回的过程,来抽象出函数头、函数体,递归出口三大条件。
代码:
class Solution {
public:
TreeNode* pruneTree(TreeNode* root)
{
if(!root) return nullptr;
root->left = pruneTree(root->left);
root-> right = pruneTree(root->right); // 如果是nullptr则直接剪枝了
if(!root->left && !root->right && root->val == 0) return nullptr;
else return root;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
98. 验证二叉搜索树
个人解
思路:
- 子问题:给一个根节点,判断这棵树是不是二叉搜索树,并且记录当前数的最小值和最大值(要用
long long
,因为要比所有int
小 / 大) - 函数体:判断左右子树是否是二叉搜索树,比较当前节点的值和左右孩子的值
- 递归出口:节点为空
屎山代码:
class Solution {
public:
bool isValidBST(TreeNode* root, long long left = LLONG_MIN, long long right = LLONG_MAX)
{
if(root == nullptr) return true;
long long x = root->val;
return left < x && x < right &&
isValidBST(root->left, left, x) &&
isValidBST(root->right, x, right);
}
};
时间复杂度:O(n)
空间复杂度:O(n)
当然也可以用中序遍历,因为搜索二叉树的中序遍历一定是一个有序数组!
230. 二叉搜索树中第 K 小的元素
个人解
思路:
- 二叉搜索树的中序遍历一定是一个有序序列,取第 k 个数
屎山代码:
class Solution {
public:
int ans;
int cnt = 0;
void dfs(TreeNode* root, int k)
{
if(!root || cnt == k) return;
dfs(root->left, k);
cnt++;
if(cnt == k) ans = root->val;
dfs(root->right, k);
}
int kthSmallest(TreeNode* root, int k)
{
dfs(root, k);
return ans;
}
};
时间复杂度:O (H + k)
空间复杂度:O (H)
257. 二叉树的所有路径
个人解
思路:
// 子问题:给一个根节点,返回所有路径
// 函数体:(根节点 + 左子树所有路径) + (根节点 + 右子树所有路径)
// 递归出口:当节点为空
屎山代码(通过):
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root)
{
vector<string> ans;
if(!root)
return ans;
string cur = to_string(root->val);
if(!root->left && !root->right)
{
ans.emplace_back(cur);
return ans;
}
if(root->left)
{
vector<string> ans_left = binaryTreePaths(root->left);
for(auto &s: ans_left)
{
s = cur + "->" + s;
ans.emplace_back(s);
}
}
if(root->right)
{
vector<string> ans_right = binaryTreePaths(root->right);
for(auto &s: ans_right)
{
s = cur + "->" + s;
ans.emplace_back(s);
}
}
return ans;
}
};
时间复杂度:O(
n
2
n^2
n2)
空间复杂度:O(
n
2
n^2
n2)
优质解
思路:
从上往下添加节点,直到添加完根节点就直接把这条路径添加到全局变量ans
里。
回溯
利用:全局变量 + 回溯 + 剪枝
- 全局变量
vecotr<string> ans
:记录每一条到叶节点后,返回的路径
- 回溯:只要有递归,就会有回溯(只是有的题用了,有的题没用)
- 往上回溯的时候,要恢复现场(本题中就是把下一层添加的节点去掉)
- 恢复现场
- 本题不用全局变量
path
恢复现场(因为如果是全局变量,不好修改下层返回的字符串) - 用函数参数
path
恢复现场:函数参数在每一个栈帧里都有,而且在每一个函数调用体内是不一样的 - 所以我们在函数内修改path,不会影响别的栈帧的path,所以函数帮助了我们恢复现场
- 本题不用全局变量
- 剪枝
- 本题剪枝就是:如果发现节点为空就不进去了
代码:
class Solution {
public:
vector<string> ans;
void dfs(TreeNode* root, string path)
{
path += to_string(root->val);
if(!root->left && !root->right)
{
ans.emplace_back(path);
return;
}
path += "->";
if(root->left)
dfs(root->left, path);
if(root->right)
dfs(root->right, path);
}
vector<string> binaryTreePaths(TreeNode* root)
{
string path;
dfs(root, path);
return ans;
}
};
时间复杂度:O(
n
2
n^2
n2),访问时间O(n),对path的拷贝O(n)
空间复杂度:O(
n
2
n^2
n2)
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!