文章目录
📝前言
本章节是总结学习二叉树,排序算法等等递归问题所总结的,对递归,搜索,回溯的算法进行总结
🌺 递归
🌸 什么是递归
函数自己调用自己的情况
🌸 为什么会用到递归?
本质:解决一个问题,出现相同的子问题
- [ 主问题] ->相同的子问题
- [ 子问题] ->相同的子问题
- …
🌸 如何理解递归?
- 分为三个阶段
- 递归展开的细节图
- 二叉树中的题目
- 重点:宏观看待递归的过程
- 不要在意递归的细节展开图
- 把递归的函数当成一个黑盒
- 相信这个黑盒一定能完成这个任务
例子展示:
//后序遍历
void dfs(TreeNode* root)
{
//细节 - 出口
if (root == nullptr)
return;
dfs(root->left);//只需相信dfs这个黑盒能帮我完成遍历左子树任务,不需要关注细节展开图
dfs(root->right);//只需相信dfs这个黑盒能帮我完成遍历右子树任务,不需要关注细节展开图
cout << root->val;
}
class Solution {
public:
void _merger(vector<int>& nums, int left, int right, int* tmp)
{
//细节 - 出口
if (left >= right)
return;
int mid = (left + right) / 2;
_merger(nums, left, mid, tmp);//只需相信给你中间值和需要参数_merge这个黑盒能帮我完成排序左区间,不需要关注细节展开图
_merger(nums, mid + 1, right, tmp);
//只需相信给你中间值和需要参数_merge这个黑盒能帮我完成排序右区间,不需要关注细节展开图
//merge操作..
// int begin1 = left, end1 = mid;
// int begin2 = mid + 1, end2 = right;
// int i = left;
// while (begin1 <= end1 && begin2 <= end2)
// {
// if (nums[begin1] <= nums[begin2])
// {
// tmp[i++] = nums[begin1++];
// }
// else
// {
// tmp[i++] = nums[begin2++];
// }
// }
// while (begin1 <= end1)
// {
// tmp[i++] = nums[begin1++];
// }
// while (begin2 <= end2)
// {
// tmp[i++] = nums[begin2++];
// }
// memcpy(nums.data() + left, tmp + left, (right - left + 1) * sizeof(int));
//}
//vector<int> sortArray(vector<int>& nums) {
// int* tmp = new int[nums.size()];
// _merger(nums, 0, nums.size() - 1, tmp);
// delete[] tmp;
// return nums;
//}
};
🌸 如何写好一个递归
- [目的:函数体的设计 ] 先找到相同的子问题
- [目的:函数体的书写 ] 只关心某一个子问题是如何解决的
- [ 避免死循环] 注意一下递归函数的出口即可
🌺搜索总结
🌸 深度优先遍历vs深度优先搜索vs宽度优先遍历 vs宽度优先搜索
- 搜索就是在遍历的时候,访问结点的值,那么**vs就是等同于的意思**
- 深度优先遍历 vs 深度优先搜索
- 宽度优先遍历 vs 宽度优先搜索
- 因此遍历是形式,目的是搜索
🌸 搜索vs暴搜关系图
搜索:暴力枚举一遍所有的情况
搜索等同于暴搜:两种方法进行
- bfs
- dfs
🌸 拓展搜索问题
将一个问题进行一 一罗列(全排列)出所有的可能组合,然后用树状图的方法来画出决策树
🌼回溯与剪枝
-
回溯算法:(本质是回退)深搜dfs
回溯算法是一种通过探索所有可能的候选解来解决决策问题的算法。
它采用试错的思想,在进行决策时,如果当前的选择导致之后无法得到有效的解决方案,则会退回到上一个决策点,并选择另一种选择。 -
剪枝:
剪枝是回溯算法中的一种优化技术,它通过分析当前的局部状态,来提前判断某个解决方案是否可行,不可行就剪掉,好比剪掉一个叶子或者一个子树,从而避免不必要的后续计算。
回溯算法的特点是先尝试并检查解决方案,如果当前解决方案不可行,就回到上一个决策点继续尝试其他的可能性。
后续文章继续继续总结