LeetCode513:找树的左下角的值
思路:利用层序遍历,每次result记录最左侧的节点,到最后一层result就更新为树的左下角。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int findBottomLeftValue(TreeNode root) {
if(root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int result = root.val;
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
if(i==0){// 记录最左侧节点的值
result = node.val;
}
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
}
return result;
}
}
层序遍历会更加简单一点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int ans = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size = que.size();
for(int i=0;i<size;i++){
TreeNode* node = que.front();
if(i==0){
ans = node->val;
}
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return ans;
}
};
LeetCode112:路径总和
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
// 递归+回溯
if(root == null){
return false;
}
boolean ans = helper(root, targetSum - root.val);// 在开始的位置对root特殊处理。不能放到里面去处理 会重复减。
return ans;
}
public boolean helper(TreeNode node, int number){
// 递归终止条件
if(node.left == null && node.right == null && number == 0){
return true;
}
else if(node.left == null && node.right == null && number != 0){
return false;
}
if(node.left!=null){
number -= node.left.val; //
if(helper(node.left, number)){
return true;
}
number += node.left.val; // 回溯
}
if(node.right!=null){
number -= node.right.val;
if(helper(node.right, number)){
return true;
}
number += node.right.val;
}
return false;
}
}
C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
bool getPath(TreeNode* node, int targetSum){
// 递归的结束条件 有两个:
// 1. 到了叶子节点 找到了;2. 到了叶子节点没有找到
if(targetSum == 0 && node->left == NULL && node->right == NULL) return true;
else if(targetSum != 0 && node->left == NULL && node->right == NULL) return false;
if(node->left){
if(getPath(node->left, targetSum - node->left->val)) // 如果下一层返回的是true 就直接向上返回true。 而且这里最好是这样写判断 不要在想之前一样写一个bool left再放到后面return 判断。
return true;
}
if(node->right){
if(getPath(node->right, targetSum - node->right->val))
return true;
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == NULL) return false;
bool ans = getPath(root, targetSum-root->val);
return ans;
}
};
LeetCode113路径总和2
思路:与上题基本一致,只不过返回的结果是具体的路径。所以更能体现回溯的价值。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
//
List<List<Integer>> ans = new ArrayList<List<Integer>>();
if(root == null){
return ans;
}
List<Integer> temp = new LinkedList<>();
helper(root, targetSum-root.val, ans, temp);
return ans;
}
public void helper(TreeNode node, int number, List<List<Integer>> ans, List<Integer> temp){
temp.add(node.val);
if(node.left == null && node.right == null && number == 0){
List<Integer> temp_ = new ArrayList<>(temp);
ans.add(temp_);
}
else if(node.left == null && node.right == null && number!=0){
return;
}
if(node.left != null){
helper(node.left, number - node.left.val, ans, temp);
temp.remove(temp.size() -1);
}
if(node.right != null){
helper(node.right, number- node.right.val, ans, temp);
temp.remove(temp.size() -1);
}
}
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
void traversal(TreeNode* node, int targetSum, vector<int>& ans_, vector<vector<int>>& ans){
// 递归结束条件,还是要找到叶子结点判断val是否为零两种情况。
// 这里的返回值设为viod比较好,不然范围ans_ 还是ans都是很麻烦的事,因此使用全局变量 或者传递这个变量比较好
if(node->left == NULL && node->right == NULL && targetSum == 0){
ans.push_back(ans_); // 找到了路径就在此时将找到的路径加到最终的二维数组去
return;
}
if(node->left== NULL && node->right == NULL){
return;
}
if(node->left){
ans_.push_back(node->left->val); // 先将当前左子节点加到ans_ 里面去
targetSum -= node->left->val; // 先将当前左子节点的val剪掉,
traversal(node->left, targetSum, ans_, ans); // 递归,此时判断左子节点下面的路径时候符合要求
targetSum += node->left->val; // 回溯, 将上一步加进去的左叶子节点值加回去,意味着返回父节点要往右子节点找了
ans_.pop_back(); // 回溯
}
if(node->right){
ans_.push_back(node->right->val);
targetSum -= node->right->val;
traversal(node->right, targetSum, ans_, ans);
targetSum += node->right->val;
ans_.pop_back();
}
return;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
// 这里必须用到回溯了,要返回所有的路径情况
vector<vector<int>> ans;
vector<int> ans_;
ans.clear();
ans_.clear();
if(root == NULL) return ans;
ans_.push_back(root->val); // 根节点在一开始就要加到ans_里面去
traversal(root, targetSum- root->val, ans_, ans);
return ans;
}
};
LeetCode106从中序和后序遍历构造二叉树
思路:
后序确定父节点,中序确定左右子树
- 通过后序找到根节点
- 通过根节点的值,在中序中遍历将其划分左右子树
- 通过左子树大小,在后序中遍历得到左,再得到右,(记得先将根节点删去)
- 递归中序和后序的左子树;递归中序和后序的右子树
- 返回root
关键点:在数组问题上 会遇见的左闭右开还是左闭右闭的问题,这里用的是左闭右闭。
有很多细节,例如:
- 使用public 一个map用来存放数组的值和索引,避免重复创建数组;
- 在递归传入参数的时候传递了inorder 和postorder的首位索引注意区间的开闭
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public Map<Integer, Integer> map = new HashMap<>();
// 用map可以方便得到元素在数组中的索引和值。
// 同时代码中没必要将左右区间都用数组表示出来,只要知道首尾索引就可以
public TreeNode buildTree(int[] inorder, int[] postorder) {
for(int i=0;i<inorder.length;i++){
map.put(inorder[i], i);
}
return getNode(inorder, 0, inorder.length -1, postorder, 0, postorder.length-1);// 这里是左闭右闭
}
public TreeNode getNode(int[] inorder, int inStart, int inEnd, int[] postorder, int poStart, int poEnd){
// 后序确定父节点,中序确定左右子树
// 1. 通过后序找到根节点
// 2. 通过根节点的值,在中序中遍历将其划分左右子树
// 3. 通过左子树大小,在后序中遍历得到左,再得到右,(记得先将根节点删去)
// 4. 递归中序和后序的左子树;递归中序和后序的右子树
// 5. 返回root
if (inStart> inEnd || poStart > poEnd) { // 不满足左闭右开,说明没有元素,返回空树
return null;
}
// 下面的写法避免了重复创建数组来保存左右区间
// 但是理解起来麻烦了点
//
int index = map.get(postorder[poEnd]); // 确定父节点的位置
TreeNode root = new TreeNode(postorder[poEnd]);
int indexLeft = index - inStart; // 确定左区间的长度,从而也可以得到有区间的长度。
root.left = getNode(inorder, inStart, index-1, postorder, poStart, poStart+indexLeft-1);
root.right = getNode(inorder, index+1,inEnd, postorder, poStart+indexLeft, poEnd-1);
return root;
}
}
完整的模板代码 便于理解。
class Solution {
private:
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 delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// postorder 舍弃末尾元素
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->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
LeetCode105从前序和中序遍历序列构造二叉树
同116题一致。注意数组的左开右闭以及在递归时候**传入参数))的细节。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for(int i=0;i<inorder.length;i++){
map.put(inorder[i], i);
}
return getNode(preorder, 0, preorder.length-1, inorder, 0, inorder.length-1);
}
public TreeNode getNode(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
if(preStart>preEnd || inStart>inEnd){
return null;
}
int index = map.get(preorder[preStart]);
TreeNode root = new TreeNode(preorder[preStart]);
int lenLeft = index -inStart;
root.left = getNode(preorder, preStart+1, preStart+lenLeft, inorder, inStart, inStart+lenLeft-1);
root.right = getNode(preorder,preStart+lenLeft+1, preEnd, inorder, index+1, inEnd);
return root;
}
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder){
if(preorder.size() == 0) return NULL;
int nodeValue = preorder[0];
TreeNode* node =new TreeNode(nodeValue);
if(preorder.size() == 1)return node;
int cutIndex;
for(cutIndex=0;cutIndex<inorder.size();cutIndex++){
if(inorder[cutIndex] == nodeValue) break;
}
vector<int> leftinorder(inorder.begin(), inorder.begin()+cutIndex);
vector<int> rightinorder(inorder.begin()+cutIndex+1, inorder.end());
vector<int> leftpreorder(preorder.begin()+1, preorder.begin()+1 + leftinorder.size());
vector<int> rightpreorder(preorder.begin()+1+leftinorder.size(), preorder.end());
node->left = traversal(leftpreorder, leftinorder);
node->right = traversal(rightpreorder, rightinorder);
return node;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0 || inorder.size() == 0) return NULL;
return traversal(preorder, inorder);
}
};