本文主要是介绍算法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.从前序与中序遍历序列构造二叉树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!