当前位置: 首页 > news >正文

剑指offer经典题目(六)

目录

回溯相关

topK问题 


回溯相关

        题目一:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点 开始往下一直到叶结点所经过的结点形成一条路径。

OJ地址

        图示如下。 

        要解决当前的问题,其实就涉及到了算法中一个思想,就是回溯的思想,这个题目也是一个经典的 DFS(深度优先遍历)+回溯法+递归 题型。

        何为回溯法?

        像二叉树的先序遍历,中序遍历,后续遍历就是很明显的回溯法。我们以中序遍历为例,我们第一个访问的节点一定是左子树中最左的节点,然后再访问当前的最左的节点的根节点,然后再去访问当前根节点的右子树,将最左的节点,最左节点的根节点,最左节点的根节点的右子树都访问完之后,当前的这个根节点可能就是上一个树的左子树或者右子树,如果是上一个树的左子树,就访问上一个树的根节点,如果是上一个树的右子树,就表示上一个树就已经访问完,然后再去判断上一个树是上一个树的左子树还是右子树,依次向上回溯,最终实现整个树的中序访问。这就是一个典型的回溯法。

        对于回溯法,我们主要分为四步。

  1. 添加待选结果,这个结果可能是最终结果,也可能不是最终结果。
  2. 判定待选结果中符合条件的结果,将符合条件的结果加入结果集。
  3. DFS,进行深度遍历。
  4. 回退,递归检测下一个待选结果。

        编码如下。

/*** struct TreeNode {*  int val;*  struct TreeNode *left;*  struct TreeNode *right;*  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* };*/
class Solution {public:void  FindPathHelper(TreeNode* root, int target, vector<vector<int>>& result,vector<int>& v) {if (root == nullptr) {return;}v.push_back(root->val);target -= root->val;if (target == 0 && root->left == nullptr && root->right == nullptr) {result.push_back(v);}//获取左子树的结果集FindPathHelper(root->left, target, result, v);//获取右子树的结果集FindPathHelper(root->right, target, result, v);v.pop_back();}vector<vector<int> > FindPath(TreeNode* root, int target) {vector<vector<int>> result; //结果集vector<int> v;//结果集if (root != nullptr) {FindPathHelper(root, target, result, v);}return result;}
};

        题目二: 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出 来的所有字符串abc,acb,bac,bca,cab和cba。OJ地址

        图示如下。

        题目解析: 全排列的问题,也可以看成一个多叉树的 DFS+回溯+递归

        我们可以直接确定a,b,c 三个节点的位置,然后再去通过递归的方式去获取其它元素的排列种类数。

 

        编码如下。

class Solution {public:void swap(string& str, int start, int i) {int temp = str[start];str[start] = str[i];str[i] = temp;}void PermutationHelper(string& str, int start, unordered_set<string>& s) {if (start == str.size() - 1) {s.insert(str);return;}//for循环可以理解为是求每一个字符作为首字符时的字符组合的种类数for (int i = start; i < str.size(); i++) {swap(str, start,i); //确定第一个字符的位置,然后去求剩下的字符的组合数PermutationHelper(str, start + 1, s);swap(str, start, i);}}vector<string> Permutation(string str) {vector<string> result;//结果集//string s;//待选结果unordered_set<string> s;//对结果集中的元素进行去重if (str.size()) {PermutationHelper(str, 0, s);result.insert(result.begin(), s.begin(), s.end());sort(result.begin(), result.end());}return result;}
};

topK 问题 

        题目三:输入 n 个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。 OJ地址

        图示如下。

        题目解析:这个题目不建议使用排序的方法解决,而是建议使用堆的思想来解决。

        回顾一下,什么是堆,堆其实就是一个完全二叉树,堆顶的元素是完全二叉树中最大的或者是最小的元素,这取决于该堆是大堆还是小堆,要解决这种问题我们可以使用建立 K 个数的大堆,为什么要建立 K 个数的大堆,大家可以去数据结构专栏查看堆那一章节的知识,这里不做过多解释。

        但是我们知道,在 stl 容器中,有一个天然是大堆的容器,就是 priority_queue 优先级队列,所以我们可以使用优先级队列查找最小的前 K 个数。

        编码如下。

#include <queue>
class Solution {public:vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {vector<int> result;if (input.size() == 0 || k == 0 || input.size() < k) {return result;}//priority_queue默认是大堆,如果要建小堆,需要自己定义仿函数priority_queue<int> q;for (int i = 0; i < input.size(); i++) {if (i < k) {q.push(input[i]);} else {if (q.top() > input[i]) {q.pop();q.push(input[i]);}}}for (int i = 0; i < k; i++) {result.push_back(q.top());q.pop();}return result;}
};

        以上便是本期的所有内容。

        本期内容到此结束^_^ 

相关文章:

  • OTA和IAP的关系
  • TI---UART通信
  • 10:00面试,10:08就出来了,面试问的问题太。。。
  • 240426 leetcode exercises
  • 启动你的RocketMQ之旅(六)-Broker详细——主从复制
  • 如何在 PowerShell 脚本中调用外部 Windows 命令
  • TypeScript基础数据类型详解
  • [论文解析]Mip-Splatting: Alias-free 3D Gaussian Splatting
  • 【Java面试笔记:进阶】22.AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
  • 自然语言处理——语言转换
  • Java社区门诊系统源码 SaaS医院门诊系统源码 可上线运营
  • 怎样理解ceph?
  • mac笔记本安装brew、nvm、git等完整版
  • AI数字人:未来职业的重塑(9/10)
  • react的fiber 用法
  • 启动 n8n 步骤指南
  • [C++ 11] --- 线程异步
  • 2025新版修复蛇年运势测试风水起名系统源码
  • 常见的六种大语言模型微调框架
  • 【MATLAB第118期】基于MATLAB的双通道CNN多输入单输出分类预测方法
  • 来论|如何看待韩企在美申请“饺子”专利
  • 泽连斯基公布与特朗普会晤细节,强调实现全面、无条件停火
  • 对外投资增长、消费市场持续升温,中国经济砥砺前行
  • 面对面倾听群众意见建议,及时回应解决群众“急难愁盼”问题!龚正在基层开展下访活动,调研城市更新
  • 马上评丨老师要求犯错学生当众道歉,不该成被告
  • 体坛联播|AC米兰挺进意大利杯决赛,弗雷戴特宣布退役