513. 找树左下角的值
心得
- 考虑层序求第一个即可,理解最深,最左
题解
-
迭代最好理解
-
对于递归法,
- 本题注意理解最深最左,最深要求深度最大,最左保证遍历顺序先左后右即,所以前中后序都可以,左右顺序都是一致的
- 对于中的逻辑本题没有的,所以三种遍历顺序均可,然后保证先左后右即可
- 同时需要回溯,往下过程中需要回去再往下,所以需要回溯,精简版本通过值传递隐藏了回溯过程,实际是存在的
// 层序
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
int result = 0;
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;
}
};
// 递归——前序
class Solution {
public:
int maxDepth = INT_MIN;
int result = 0;
void traversal(TreeNode* cur, int depth) {
if (cur == nullptr) return ;
if (cur->left == nullptr && cur->right == nullptr) {
if (depth > maxDepth) {
maxDepth = depth;
result = cur->val;
}
}
if (cur->left) {
depth++;
traversal(cur->left, depth);
depth--; // 回溯
}
if (cur->right) {
depth++;
traversal(cur->right, depth);
depth--; // 回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
};
// 递归——精简版
void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) {
if (depth > maxDepth) {
maxDepth = depth;
result = root->val;
}
return;
}
if (root->left) {
traversal(root->left, depth + 1); // 隐藏着回溯,值传递,不会改变变量
}
if (root->right) {
traversal(root->right, depth + 1); // 隐藏着回溯,值传递,不会改变变量
}
return;
}
112. 路径总和
写递归函数是否需要返回值
- 本题,这种只要找到一条路径,就立即返回,不需要完全找完,这种需要返回值递归返回
- 需要搜索一棵二叉树不需要处理递归返回值,则不需要返回值,如113
- 需要搜索一棵二叉树且需要处理递归返回值,则需要返回值,如236
心得
- 递归法,考虑其实由于中没有处理逻辑,前中后序遍历均可,形参隐藏回溯,多总结,多思考
- 直接AC
题解
- 写的直接精简版本,可以考虑复原回溯过程的代码
- 迭代用的栈,不仅记录指针而且记录路径总和
// 递归-体现回溯,第一次进递归时,已经减去根结点值,所以后面都是判断0,
class Solution {
private:
bool traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回
if (cur->left) { // 左
count -= cur->left->val; // 递归,处理节点;
if (traversal(cur->left, count)) return true;
count += cur->left->val; // 回溯,撤销处理结果
}
if (cur->right) { // 右
count -= cur->right->val; // 递归,处理节点;
if (traversal(cur->right, count)) return true;
count += cur->right->val; // 回溯,撤销处理结果
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int sum) {
if (root == NULL) return false;
return traversal(root, sum - root->val);
}
};
// 递归——精简版
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
if (!root->left && !root->right) {
if (targetSum == root->val) {
return true;
}
}
return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}
};
// 迭代法
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
stack<pair<TreeNode*, int>> st;
if (root == nullptr) return false;
st.push(pair<TreeNode*, int>(root, root->val));
while (!st.empty()) {
pair<TreeNode*, int> node = st.top();
st.pop();
if (!node.first->left && !node.first->right && targetSum == node.second) {
return true;
}
if (node.first->left) st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
if (node.first->right) st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
}
return false;
}
};
113. 路径总和 II
心得
- 想的是用引用传参vector和vector>,其实用全局变量会方便很多
题解
- 思路同112,不过添加vector保存位置
- 注意回溯,vector路径也要回溯
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void traversal(TreeNode* cur, int count) {
// 不同添加,在调用时就已经添加本层节点
if (!cur->left && !cur->right && count == 0) { // 叶子结点
result.push_back(path);
}
if (!cur->left && !cur->right) return;
if (cur->left) {
path.push_back(cur->left->val);
count -= cur->left->val;
traversal(cur->left, count);
count += cur->left->val;
path.pop_back();
}
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 == nullptr) return result;
path.push_back(root->val);
traversal(root, targetSum - root->val);
return result;
}
};
106. 从中序与后序遍历序列构造二叉树
心得
- 过程想的很清楚,一写各种问题
题解
- 前序和中序、后序和中序都可以构造出唯一二叉树
- 本题来说,后序的最后一个一定是根节点,然后以此为界分割前序,然后得前序左右,然后以此左右size一致特点,切割后序,然后递归即可
- 注意分割时,剔除分割点,后序resize,前序index跳1等
// 递归——详细版
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
// 1.终止条件
if (inorder.size() == 0) return nullptr;
// 2.确定分割点的值
int rootvalue = postorder[postorder.size() - 1];
// 构造结点
TreeNode* root = new TreeNode(rootvalue);
// 3.叶子结点直接返回
if (inorder.size() == 1) return root;
// 确定分割点
int delimitValue = 0;
for (delimitValue = 0; delimitValue < inorder.size(); delimitValue++) {
if (inorder[delimitValue] == rootvalue) break;
}
// 确保统一变量,均采用左闭右开
// 4.分割中序为左中 右中两半
vector<int> leftInorder = vector<int>(inorder.begin(), inorder.begin() + delimitValue);
vector<int> rightInorder = vector<int>(inorder.begin() + delimitValue + 1, inorder.end()); // 中间结点除外
// 丢弃刚用过的中结点
postorder.resize(postorder.size() - 1);
// 5.根据中序中size一致来分割分割后序为左后,右后
vector<int> leftPostorder = vector<int>(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder = vector<int>(postorder.begin() + leftInorder.size(), postorder.end());
// 6. 递归构建左右子树
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0) return nullptr;
return traversal(inorder, postorder);
}
// 递归——优化版,index来调用
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, int inorderBegin, int inorderEnd,
vector<int>& postorder, int postorderBegin, int postorderEnd) {
if (inorderBegin == inorderEnd) return nullptr;
int rootValue = postorder[postorderEnd - 1];
TreeNode* root = new TreeNode(rootValue);
if (inorderEnd - inorderBegin == 1) return root;
int delimiterIndex = inorderBegin;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderBegin = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0) return nullptr;
return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
心得
题解
- 如后序和中序构造一般,注意细节,注意debug
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, int preorderBegin, int preorderEnd, vector<int>& inorder, int inorderBegin, int inorderEnd) {
if (preorderEnd - preorderBegin == 0) return nullptr;
int rootValue = preorder[preorderBegin];
TreeNode* root = new TreeNode(rootValue);
if (preorderEnd - preorderBegin == 1) return root;
int delimiterIndex = inorderBegin;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 坚持左闭右开
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 中序size,由于右开,end - start即为大小
int rightPreorderBegin = leftPreorderEnd;
int rightPreorderEnd = preorderEnd;
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex; // 注意不要+begin,此时index为实际而不是差值
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
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) {
if (preorder.size() == 0 || inorder.size() == 0) return nullptr;
return traversal(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}
};