学习目标:
- 513.找树左下角的值
- 112.路径总和
- 113.路径总和ii
- 106.从中序与后序遍历序列构造二叉树
- 105.从前序与中序遍历序列构造二叉树
学习内容:
513.找树左下角的值
题目链接&&文章讲解
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层最左边节点的值。
假设二叉树中至少有一个节点。
//递归法
class Solution {
private int maxDepth = -1;
private int result = 0;
//确定递归函数的参数和返回值
//参数:节点,深度
//返回值:void
public void traversal(TreeNode node, int depth){
//确定终止条件:叶子节点
if(node.left == null && node.right == null){
if(depth > maxDepth) {
maxDepth = depth;
result = node.val;
}
return;
}
//处理逻辑
if(node.left != null){
depth++;
traversal(node.left, depth);
depth--;
}
if(node.right != null){
depth++;
traversal(node.right, depth);
depth--;//回溯
}
}
public int findBottomLeftValue(TreeNode root) {
result = root.val;
traversal(root,0);
return result;
}
}
//迭代法(层序遍历)
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> que = new LinkedList<>();
if(root != null) que.offer(root);
int res = 0;
while(!que.isEmpty()){
int size = que.size();
for(int i = 0; i < size; i++){
TreeNode node = que.poll();
//记录每层第一个元素
if (i == 0) {
res = node.val;
}
if(node.left != null) que.offer(node.left);
if(node.right != null) que.offer(node.right);
}
}
return res;
}
}
112.路径总和
题目链接 &&文章讲解
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
class Solution {
public boolean traversal(TreeNode node, int count){
//终止条件:叶子节点
if(node.left == null && node.right == null && count ==0) return true;
if(node.left == null && node.right == null && count !=0) return false;
//处理逻辑
if(node.left != null){
count = count - node.left.val;
if(traversal(node.left,count)) return true;
count = count + node.left.val;//回溯
}
if(node.right != null){
count = count - node.right.val;
if(traversal(node.right,count)) return true;
count = count + node.right.val;//回溯
}
return false;
}
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
return traversal(root,targetSum - root.val);
}
}
13.路径总和ii
题目链接 &&文章讲解
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
List<Integer> path = new ArrayList<>();
traverval(root, targetSum - root.val, res, path);
return res;
}
public void traverval(TreeNode node, int count, List<List<Integer>> res,List<Integer> path){
path.add(node.val);
//确定终止条件
if(node.left == null && node.right == null && count == 0) {
res.add(new ArrayList<>(path));
return;
}
if(node.left == null && node.right == null && count != 0) return;
//处理逻辑
if(node.left != null){
count = count - node.left.val;
traverval(node.left,count,res,path);
count = count + node.left.val;//回溯
path.remove(path.size() - 1); //回溯
}
if(node.right != null){
count = count - node.right.val;
traverval(node.right,count,res,path);
count = count + node.right.val;//回溯
path.remove(path.size() - 1); //回溯
}
}
}
106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0 || postorder.length == 0) return null;
// 左闭右开的原则
return traversal(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
public TreeNode traversal(int[] inorder, int inorderBegin, int inorderEnd, int[] postorder, int postorderBegin, int postorderEnd){
//后序数组为0 返回空节点
if(postorderBegin == postorderEnd) return null;
//根据后序数组构造根节点
int rootValue = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootValue);
//寻找中序数组位置作为切割点
int delimiterIndex;
for(delimiterIndex = 0; delimiterIndex < inorderEnd; delimiterIndex++){
if(inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割后序数组
// 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + (delimiterIndex - inorderBegin); // 终止位置是 需要加上 中序区间的大小size
// 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了
//递归处理左右区间
root.left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root.right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
return root;
}
}
105.从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (inorder.length == 0 || preorder.length == 0) return null;
// 左闭右开的原则
return traversal(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
public TreeNode traversal(int[] preorder, int preorderBegin, int preorderEnd, int[] inorder, int inorderBegin, int inorderEnd){
//前序数组为0 返回空节点
if(preorderBegin == preorderEnd) return null;
//根据前序数组构造根节点
int rootValue = preorder[preorderBegin];
TreeNode root = new TreeNode(rootValue);
//寻找中序数组位置作为切割点
int delimiterIndex;
for(delimiterIndex = 0; delimiterIndex < inorderEnd; delimiterIndex++){
if(inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割前序数组
// 左后序区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = preorderBegin + 1+ (delimiterIndex - inorderBegin); // 终止位置是 需要加上 中序区间的大小size
// 右后序区间,左闭右开[rightPreorderBegin, rightPreorderEnd)
int rightPreorderBegin = preorderBegin + 1+ (delimiterIndex - inorderBegin);
int rightPreorderEnd = preorderEnd;
//递归处理左右区间
root.left = traversal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
root.right = traversal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);
return root;
}
}