题目:513. 找树左下角的值 - 力扣(LeetCode)
思路:
非递归:采用层序遍历的方式,遍历到最后一层的第一个节点就是最底层的最左侧节点。定义一个变量result用来记录每一层的第一个节点,在遍历每一层节点时,不断更新result,直到最后一层result里保存的就是最底层的最左侧节点的值。
代码:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
int result = 0;
if(root == NULL) return 0;
que.push(root);
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;//每遍历一层,最左侧的节点的值都刷新一次,直到找到最后一层的最左侧节点,然后退出while循环
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return result;
}
};
递归:
思路:递归遍历+回溯
返回值:bool类型,需要一层层返回目标和是否满足路径总和
终止条件:定义一个count变量初始值为目标和,每次减去遍历路径节点上的数值,当遍历到叶子节点并且count == 0时,说明找到一条路径满足目标和,返回true,如果遍历到叶子节点且不等于0,返回false
单层递归逻辑:因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。
递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。
代码:
class Solution {
public:
bool getSum(TreeNode* cur, int count){
if(cur->left == NULL && cur->right == NULL && count == 0) return true;
if(cur->left == NULL && cur->right == NULL && count != 0) return false;
if(cur->left){//左
count -= cur->left->val;//递归处理节点,count传递给下一个节点的值应该等于当前count值减去下一个节点的值,因为最后来到叶子节点是判断count是否等于0而不是等于当前节点的值
if(getSum(cur->left, count)) return true;
count += cur->left->val;//回溯,count要回到上一个节点的值,再传递到下一个右孩子
}
if(cur->right){//右
count -= cur->right->val;
if(getSum(cur->right, count)) return true;
count += cur->right->val;//回溯
}
//中
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
return root == NULL ? false : getSum(root, targetSum - root->val);
}
};
题目:113. 路径总和 II - 力扣(LeetCode)
思路:
返回值:void,因为不需要向上层返回什么信息,只需要一路收集元素,添加到path数组里
终止条件: 定义一个count变量初始值为目标和,每次减去遍历路径节点上的数值,当遍历到叶子节点并且count == 0时,说明找到一条路径满足目标和,就把这条路径加入到二维数组result里,result用来记录所有满足目标和的路径的情况。
单层递归逻辑:把路径上的元素都加入到path数组里,并且回溯count和path
代码:
class Solution {
public:
vector<vector<int>> result;//定义一个二维数组全局变量,用来收集所有的路径和的情况
vector<int> path;//定义一个一维数组用来收集一条路径上的元素
void traversal(TreeNode* cur, int count){
if(cur->left == NULL && cur->right == NULL && count == 0){
result.push_back(path);//当遍历到叶子节点并且满足和为目标和时,此时path数组已经把这条路径上的元素都收集到了,因此把这条路径加入到result里
return;//不用向上一层返回信息,只做收集处理,因此返回空
}
if(cur->left == NULL && cur->right == NULL && count != 0) return;
if(cur->left){//左
path.push_back(cur->left->val);
count -= cur->left->val;
traversal(cur->left, count);//递归处理
count += cur->left->val;//第一次回溯,处理count
path.pop_back();//第二次回溯,处理path数组里的元素
}
if(cur->right){//右
path.push_back(cur->right->val);
count -= cur->right->val;
traversal(cur->right, count);
count += cur->right->val;
path.pop_back();
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
result.clear();
path.clear();
if(root == NULL) return result;
path.push_back(root->val);//先将头结点的值传入path数组里
traversal(root, targetSum - root->val);//目标和先要减去头结点的值
return result;
}
};
题目:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
思路:
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
具体分析见:代码随想录 (programmercarl.com)
代码:
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
if(postorder.size() == 0) return NULL;
//后序遍历数组中最后一个元素就是当前的中间节点
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;
}
//切割中序数组,区间左闭右开
//左中序[0, index)
vector<int> leftinorder(inorder.begin(), inorder.begin() + index);
//右中序[index + 1, end)
vector<int> rightinorder(inorder.begin() + index + 1, inorder.end());
//将后序数组中的最后一个元素舍弃
postorder.resize(postorder.size() - 1);
//切割后序数组,区间左闭右开
//左后序[0, leftinorder.size)
vector<int> leftpostorder(postorder.begin(), postorder.begin() + leftinorder.size());
//右后序[leftinorder.size, end)
vector<int> rightpostorder(postorder.begin() + leftinorder.size(), postorder.end());
//递归处理左子树和右子树
//递归返回的是左右子树的根节点,每一层返回root,相当于root->root1->root2->root3->NULL
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 NULL;
return traversal(inorder, postorder);
}
};
题目:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
思路:见上一题
代码:
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder){
if(preorder.size() == 0) return NULL;
int rootValue = preorder[0];
TreeNode* root = new TreeNode(rootValue);
if(preorder.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());
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(inorder.size() == 0 || preorder.size() == 0) return NULL;
return traversal(preorder, inorder);
}
};