513. 找树左下角的值
层序遍历秒杀,但是我还是学写优雅的递归
class Solution {
public:
//注意这两个是全局变量
int res;
int maxDepth = INT_MIN;
void getMostLeft(TreeNode* node, int depth)
{
// 如果为叶子节点,那么开始判断
if(node->left == nullptr && node->right == nullptr)
{
if(depth > maxDepth)
{
maxDepth = depth;
res = node->val;
}
return;
}
// 必须要对node->left加一个判断
if(node->left)
{
depth++;
getMostLeft(node->left, depth);
depth--;
}
// 对node->right加一个判断
if(node->right)
{
depth++;
getMostLeft(node->right, depth);
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
// 卡哥说的迭代模板题
// queue que;
// if(root)
// que.push(root);
// while(!que.empty())
// {
// int size = que.size();
// bool flag = false;
// vector vec;
// for(int i = 0; i
// {
// TreeNode* tmp = que.front();
// que.pop();
// vec.push_back(tmp->val);
// if(tmp->left)
// {
// que.push(tmp->left);
// flag = true;
// }
// if(tmp->right)
// {
// que.push(tmp->right);
// flag = true;
// }
// }
// if(!flag)
// return *vec.begin();
// }
// return 0;
// 递归法
if (root)
getMostLeft(root,0);
return res;
}
};
112. 路径总和
同样是叶子结点的题目,对节点的左节点的右节点操作,不对节点本身操作,因此要注意根节点的单独处理。
class Solution {
public:
bool traversal(TreeNode* root, vector<int>& vec, int targetSum)
{
// 叶子结点, 就判断
if(root->left == nullptr && root->right == nullptr)
{
int sum = 0;
for(int i = 0;i < vec.size(); i++)
{
sum += vec[i];
}
if(sum == targetSum)
{
return true;
}
return false;
}
// 左节点
if(root->left)
{
vec.push_back(root->left->val);
bool res = traversal(root->left, vec, targetSum);
if(res)
return true;
// 回溯过程
vec.pop_back();
}
// 右节点
if(root->right)
{
vec.push_back(root->right->val);
bool res = traversal(root->right, vec, targetSum);
if(res)
return true;
vec.pop_back();
}
// 所有情况结束后要单独加一个返回
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
vector<int> vec;
bool res = false;
if(root == nullptr)
return false;
//由于处理的是左右孩子节点,因此需要传入的目标值要减去根节点的值
return traversal(root, vec, targetSum - root->val);
}
};
113. 路径总和 II
这题不过是加一个二维vector数组,通过引用方式传递,存储结果。精华在代码处和注释。
class Solution {
public:
void getAllPath(TreeNode* root, vector<vector<int>>& res, vector<int>& vec, int targetSum)
{
// 叶子结点单独处理
if(root->left == nullptr && root->right == nullptr)
{
int sum = 0;
for(auto i : vec)
{
sum += i;
}
// 相加和等于目标值,存入结果集
if(sum == targetSum)
{
res.push_back(vec);
}
}
// 左节点不为空
if(root->left)
{
vec.push_back(root->left->val);
getAllPath(root->left, res, vec, targetSum);
// 回溯
vec.pop_back();
}
if(root->right)
{
vec.push_back(root->right->val);
getAllPath(root->right, res, vec, targetSum);
vec.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> res;
vector<int> vec;
if(root == nullptr)
return res;
else
{
// 因为这个不对本节点处理,是对左右孩子节点处理,因此需要先把根节点存入结果
vec.push_back(root->val);
getAllPath(root, res, vec, targetSum);
}
return res;
}
};
总结:前三道题目都是对叶子结点的处理,那么就需要判断节点的左右孩子是否为空,为空则为叶子结点。同时在递归遍历之前需要对每个节点做是否为空判断。对于回溯,我一直理解递归代码都在尝试回溯,因此也不算难理解,以上代码写出了回溯的过程,即采用引用传递,节省每一层的空间;若是以前的方法则省略了回溯的过程,每一层的变量单独保存,造成空间的浪费。
106. 从中序与后序遍历序列构造二叉树
重量级题目,曾经就在想这个题目的解法,但是都搁置了,现在刷到,非常滴珍贵。
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
// 空节点返回null
if(postorder.size() == 0) return nullptr;
int rootValue = postorder[postorder.size()-1];//后序遍历最后一个数
// 新建的一个节点
TreeNode* root = new TreeNode(rootValue);
// 本句注释掉也可以
if(postorder.size() == 1) return root;
// 中序分割
int index;
for(index = 0; index < inorder.size(); index++)
{
if(inorder[index] == rootValue)
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.size() == 0 || postorder.size() == 0) return nullptr;
return traversal(inorder, postorder);
}
};
105. 从前序与中序遍历序列构造二叉树
这题和上一题差不多,是必掌握的题目。现在先按照笨方法写出来,二刷再看角标法(更省空间,时间)。
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder)
{
if(preorder.size() == 0)
return nullptr;
int rootValue = preorder[0];
TreeNode* root = new TreeNode(rootValue);
// 确定中序分割点
int index;
for(index = 0; index < inorder.size(); index++)
{
if(inorder[index] == rootValue) 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.size() == 0 || inorder.size() == 0)
return nullptr;
return traversal(preorder, inorder);
}
};