算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

本文主要是介绍算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

  • 513.找树左下角的值
    • 迭代法
  • 112. 路径总和
  • 113.路径总和Ⅱ
  • 106.从中序与后序遍历序列构造二叉树
  • 105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

一开始题意理解错了,做了好多无用功…看来读题真的非常重要。以为重点是左下角,其实题目的中的左下角必须是在最后一层。即使最后一层没有左孩子结点,只有右孩子结点,那么这个右孩子也算是树的左下角。

迭代法

class Solution {
public:int findBottomLeftValue(TreeNode* root) {queue<TreeNode*> que;que.push(root);int result;while(!que.empty()){int size=que.size();for(int i=0;i<size;i++){TreeNode*node=que.front();que.pop();if(i==0) result=node->val;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return result;}
};

迭代法我一开始也没有做出来,主要还是因为不知道该怎么去定位最后一层,我该凭什么逻辑来认定它就是最后一层呢?然后陷进去出不来了。而卡哥的解法非常巧妙:我们不管什么时候是最后一层,我先把一层里面第一个值赋给result。这样的话,第一层的第一个值赋给result,等到了的二层的时候机会自动更新为第二层的第一个值,第三层的时候以此类推… 所以当到了最后一层的时候,result就是最后一层的第一个值。只有对过程和结果的理解非常深刻才能想到这个。我们不单单看着最后一层,我们看到是整个逻辑过程

另外,除非思路贴吧清晰,否则不要使用while(n–),而要改用for(int i=0;i<n;i++)

112. 路径总和

这题还是比较简单的,代码如下:

class Solution {
public:void traversal(TreeNode*root,vector<int>&path,vector<int>& result){path.push_back(root->val);if(root->left==nullptr&&root->right==nullptr){int count=0;for(int i=0;i<path.size();i++)count+=path[i];result.push_back(count);return;}if(root->left){traversal(root->left,path,result);path.pop_back();}if(root->right){traversal(root->right,path,result);path.pop_back();}}bool hasPathSum(TreeNode* root, int targetSum) {vector<int> path;vector<int> result;int flag=false;if(root!=nullptr){traversal(root,path,result);for(int i=0;i<result.size();i++){if(result[i]==targetSum)flag=true;}}return flag;}
};

这题思路和257.二叉树的所有路径基本一致,只是把其中的一个字符串型数组改成了整数型数组,核心逻辑完全相同,属于模板题。

113.路径总和Ⅱ

这题同样很简单,只需要再加一个二位数组来接收一下路径即可。具体代码如下:

class Solution {
public:
void traversal(TreeNode*root,vector<int>&path,vector<int>& result,vector<vector<int>>&Path){path.push_back(root->val);if(root->left==nullptr&&root->right==nullptr){Path.push_back(path);int count=0;for(int i=0;i<path.size();i++)count+=path[i];result.push_back(count);return;}if(root->left){traversal(root->left,path,result,Path);path.pop_back();}if(root->right){traversal(root->right,path,result,Path);path.pop_back();}}vector<vector<int>> pathSum(TreeNode* root, int targetSum) {vector<int> path;vector<int> result;vector<vector<int>> Path;vector<vector<int>> Result;if(root!=nullptr){traversal(root,path,result,Path);for(int i=0;i<result.size();i++){if(result[i]==targetSum)Result.push_back(Path[i]);}}return Result;}
};

106.从中序与后序遍历序列构造二叉树

这题难度很大,而且其中的vector的用法我也是第一次见,一共花了一个多小时才弄明白,具体代码如下:

class Solution {
public:TreeNode*traversal(vector<int>& inorder, vector<int>& postorder){if(postorder.size()==0) return nullptr;int value=postorder[postorder.size()-1];TreeNode*root=new TreeNode(value);if(postorder.size()==1) return root;int index=0;for(;index<inorder.size();index++){if(inorder[index]==value) break;}vector<int>leftInorder(inorder.begin(),inorder.begin()+index);vector<int>rightInorder(inorder.begin()+index+1,inorder.end());postorder.resize(postorder.size()-1);vector<int>leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());vector<int>rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());root->left=traversal(leftInorder,leftPostorder);root->right=traversal(rightInorder,rightPostorder);return root;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder){if(!inorder.empty())return traversal(inorder,postorder);elsereturn nullptr;}
};

总体思路(递归):

  • 参数显然是中序数组和后序数组,返回值是结点类型(这意味肯定有函数赋值的操作)

  • 终止条件,有2个:一是当后续数组为空时(每递归依次后序数组大小都会减一),返回null,比较正常;二是当后续数组只有一个元素时,直接返回root;(可以理解成剪枝的操作)

  • 单层递归:

    • 首先,先序遍历,创造当前结点空间并赋值(从当前节点往下走,因为孩子的递归需要父节点的信息,如怎么去切割,所有要先序遍历)。

    • 然后就是重头戏:为当前的左右孩子分别切割左右中序和左右后续

      • 先切割原来的中序数组。具体方法:定义两个vector数组,把左边的数组赋值到一个vector中,再把右边的数组赋值到另一个vector中;
      • 然后再切割后续数组。具体方法:把前面的和左中序相同大小的数组赋值到一个vector中,再把剩余的数组赋值到另一个vector中(在切割需要将原后序数组的大小减一)
      • 要注意,切割的时候要保证区间的统一,要么都是左开右闭,要不都是左闭右开等等,看情况选择一个,之后所有的区间都是按照这一个逻辑进行
    • 切割完成之后,给左孩子分配左中序和左后序,给右孩子分配有右中序和右后序,递归

    • 最后别忘了返回当前结点

105.从前序与中序遍历序列构造二叉树

class Solution {
public:TreeNode*traversal(vector<int>& preorder, vector<int>& inorder){if(preorder.size()==0)return nullptr;int value=preorder[0];TreeNode*root=new TreeNode(value);if(preorder.size()==1)return root;int index=0;for(;index<inorder.size();index++){if(inorder[index]==value)break;}vector<int> leftInorder(inorder.begin(),inorder.begin()+index);vector<int> rightInorder(inorder.begin()+index+1,inorder.end());preorder.erase(preorder.begin());vector<int> leftPreorder(preorder.begin(),preorder.begin()+leftInorder.size());vector<int> rightPreorder(preorder.begin()+leftInorder.size(),preorder.end());root->left=traversal(leftPreorder,leftInorder);root->right=traversal(rightPreorder,rightInorder);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if(!preorder.empty())return traversal(preorder,inorder);else return nullptr;}
};

原理基本相同,唯一不同的是先序数组要先删除第一个元素,而前面一题是删除最后一个元素。即preorder.erase(preorder.begin())。此函数内部包含了删除之后的数组位置的重新布置以及size–

这篇关于算法day15|513.找树左下角的值、112. 路径总和、113.路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119667

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Linux修改pip和conda缓存路径的几种方法

《Linux修改pip和conda缓存路径的几种方法》在Python生态中,pip和conda是两种常见的软件包管理工具,它们在安装、更新和卸载软件包时都会使用缓存来提高效率,适当地修改它们的缓存路径... 目录一、pip 和 conda 的缓存机制1. pip 的缓存机制默认缓存路径2. conda 的缓

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

Python中Windows和macOS文件路径格式不一致的解决方法

《Python中Windows和macOS文件路径格式不一致的解决方法》在Python中,Windows和macOS的文件路径字符串格式不一致主要体现在路径分隔符上,这种差异可能导致跨平台代码在处理文... 目录方法 1:使用 os.path 模块方法 2:使用 pathlib 模块(推荐)方法 3:统一使

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

MySQL9.0默认路径安装下重置root密码

《MySQL9.0默认路径安装下重置root密码》本文主要介绍了MySQL9.0默认路径安装下重置root密码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录问题描述环境描述解决方法正常模式下修改密码报错原因问题描述mysqlChina编程采用默认安装路径,