513.找树左下角的值
题目链接:513. 找树左下角的值
迭代法
使用层次遍历,每一层中队列的队头即为该层最左值;若无下一层,则找到了左下角的值;
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size = que.size();
result = que.front()->val;
for(int i = 0; i < size; ++i){
TreeNode* node = que.front(); que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return result;
}
};
递归法
由于没有中间结点的处理逻辑,所以前中后序遍历均可;
因为遍历左总是在右之前,所以每次深度更新时一定是先遍历到最左边的结点;
class Solution {
public:
int result;
int maxDepth = 0;
void traversal(TreeNode* cur, int depth){
if(cur->left == NULL && cur->right == NULL){
if(depth > maxDepth){
maxDepth = depth;
result = cur->val;
}
}
if(cur->left) traversal(cur->left, depth + 1);
if(cur->right) traversal(cur->right, depth + 1);
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 1);
return result;
}
};
112. 路径总和 113.路径总和ii
路径总和
题目链接:112. 路径总和
迭代法
由于递归法需要回溯,我总感觉回溯比较抽象,所以我更喜欢迭代法,用栈来实现,多设一个栈用来存放根结点到当前结点的值的和;
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
stack<pair<TreeNode*, int>> st;
if(root == NULL) return false;
st.push({root, root->val});
while(!st.empty()){
TreeNode* node = st.top().first;
int sum = st.top().second;
st.pop();
if(!node->left && !node->right){
if(sum == targetSum) return true;
}
if(node->left){
st.push({node->left, sum + node->left->val});
}
if(node->right){
st.push({node->right, sum + node->right->val});
}
}
return false;
}
};
递归法
回溯其实也不难,就是我总感觉递归法很抽象;
class Solution {
public:
int target;
bool traversal(TreeNode* cur, int sum){
if(cur == NULL) return false;
sum += cur->val;
if(!cur->left && !cur->right){
if(sum == target) return true;
}
bool leftSum = traversal(cur->left, sum);
bool rightSum = traversal(cur->right, sum);
return (leftSum || rightSum);
}
bool hasPathSum(TreeNode* root, int targetSum) {
target = targetSum;
return traversal(root, 0);
}
};
路径总和II
题目链接:113. 路径总和 II
迭代法
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
stack<pair<TreeNode*, int>> st;
stack<vector<int>> path;
vector<vector<int>> result;
if(root == NULL) return result;
st.push({root, root->val});
path.push({});
while(!st.empty()){
TreeNode* node = st.top().first;
int sum = st.top().second;
st.pop();
vector<int> temp = path.top(); path.pop();
temp.push_back(node->val);
if(!node->left && !node->right){
if(sum == targetSum){
result.push_back(temp);
}
continue;
}
if(node->left){
path.push(temp);
st.push({node->left, sum + node->left->val});
}
if(node->right){
path.push(temp);
st.push({node->right, sum + node->right->val});
}
}
return result;
}
};
递归法
class Solution {
public:
vector<vector<int>> result;
int target;
void traversal(TreeNode* cur, int sum, vector<int> path){
if(cur == NULL) return;
sum += cur->val;
if(!cur->left && !cur->right){
if(sum == target){
result.push_back(path);
}
}
if(cur->left){
path.push_back(cur->left->val);
traversal(cur->left, sum, path);
path.pop_back();
}
if(cur->right){
path.push_back(cur->right->val);
traversal(cur->right, sum, path);
path.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
target = targetSum;
if(root == NULL) return result;
traversal(root, 0, {root->val});
return result;
}
};
有一些小细节可以改进,比如我递归函数里的sum参数可以改为count,即结点值之和与targetSum的差值,这样既不用再存储targetSum,也可避免相加数值过大。
106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树
106.从中序与后序遍历序列构造二叉树
题目链接:106. 从中序与后序遍历序列构造二叉树
使用递归,层层切割;
- 第一步:如果数组大小为零的话,说明是空节点了。
- 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
- 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
- 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
- 第五步:切割后序数组,切成后序左数组和后序右数组
- 第六步:递归处理左区间和右区间
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
// 若结点为空
if(postorder.size() == 0) return NULL;
// 结点不为空
int rootVal = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootVal);
// 若为叶结点
if(inorder.size() == 1) return root;
// 切割中序遍历
int index;
for(index = 0; index < inorder.size(); ++index){
if(inorder[index] == rootVal) 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) {
TreeNode* root = traversal(inorder, postorder);
return root;
}
};
递归函数中新建了许多vector数组,其实没必要,只需要记录下左右切割的数组下标即可;
105.从前序与中序遍历序列构造二叉树
题目链接:105. 从前序与中序遍历序列构造二叉树
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, int preorderBegin, int preorderEnd, vector<int>& inorder, int inorderBegin, int inorderEnd){
// 若为空结点
if(preorderBegin == preorderEnd) return NULL;
// 不为空结点
int rootVal = preorder[preorderBegin];
TreeNode* root = new TreeNode(rootVal);
// 若为叶结点
if(preorderEnd - preorderBegin == 1) return root;
// 切割中序遍历序列
int index;
for(index = inorderBegin; index < inorderEnd; ++index){
if(inorder[index] == rootVal) break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = index;
int rightInorderBegin = index + 1;
int rightInorderEnd = inorderEnd;
// 切割前序遍历序列
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = leftPreorderBegin + leftInorderEnd - leftInorderBegin;
int rightPreorderBegin = leftPreorderEnd;
int rightPreorderEnd = preorderEnd;
// 递归
root->left = traversal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
root->right = traversal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int size = preorder.size();
TreeNode* root = traversal(preorder, 0, size, inorder, 0, size);
return root;
}
};