1 513. 找树左下角的值
题目:给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。
提示:
- 二叉树的节点个数的范围是
[1,104]
-231 <= Node.val <= 231 - 1
思路:寻找树左下角的值,目标为树最低层,最左边的节点的值。这里注意如果这棵树最低层只有右叶子节点,但它相对来说也是最低层的左边 ,因此本题采用层序遍历,记录每层遍历的第一个节点的值即可。
注意:左下角是相对位置,右子树的右叶子节点也可以是“左下角”,层序遍历中注意比较层数是否为最深。
Java实现
/**
* 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 {
private int Deep = -1;
private int value = 0;
public int findBottomLeftValue(TreeNode root) {
value = root.val;
findLeftValue(root,0);
return value;
}
private void findLeftValue(TreeNode root,int deep){
if(root == null){
return ;
}
if(root.left == null && root.right == null){
if(deep>Deep){
value = root.val;
Deep = deep;
}
}
if(root.left != null){
findLeftValue(root.left,deep+1);
}
if(root.right != null){
findLeftValue(root.right,deep+1);
}
}
}
2 112. 路径总和
题目: 给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。叶子节点 是指没有子节点的节点。
提示:
- 树中节点的数目在范围
[0, 5000]
内 -1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
思路:本题主要思路和 257. 二叉树的所有路径 一致,不同之处在于路径信息不输出,只进行比较,是否存在满足条件的距离总和。
注意:注意回溯
Java实现
/**
* 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 {
private boolean result = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null){
return result;
}
List<Integer> path = new ArrayList<>();
equalPathSum(root,path,targetSum);
return result;
}
private void equalPathSum(TreeNode root,List<Integer> path,int targetSum){
path.add(root.val);
if(root.left==null && root.right==null){ // 遇到叶子节点判断当前路径和是否满足条件
int sum =0;
for(int i=0;i<path.size();i++){
sum += path.get(i);
}
if(sum==targetSum){
result = true;
}
return ;
}
// 递归和回溯
if(root.left!=null){
equalPathSum(root.left,path,targetSum);
path.remove(path.size()-1);
}
if(root.right!=null){
equalPathSum(root.right,path,targetSum);
path.remove(path.size()-1);
}
}
}
3 106. 从中序与后序遍历序列构造二叉树
题目: 给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
和postorder
都由 不同 的值组成postorder
中每一个值都在inorder
中inorder
保证是树的中序遍历postorder
保证是树的后序遍历
思路:根据后续遍历和中序遍历的数组生成原树,首先要明确后续遍历和中序遍历如何划分左右子树。后续遍历,从尾到头依次为根节点、右子树、左子树;中序遍历,从头到尾依次为左子树、根节点、右子树。根据不同遍历顺序的特点,结合使用。取后续遍历的最后一个元素,即为当前根节点,在中序遍历的数组中找到其下标位置,下标以前的都是左子树的部分,下标以后的都为右子树的部分,据此划分出两个新的中序遍历表。根据新生成的中序遍历中的元素个数划分出新的后续遍历表,这里注意,后续遍历表每次都从后向前退一个元素。
注意:本题基本思路在于划分,切割。在确定划分界限后,切割的区间范围要界定明了。
Java实现
/**
* 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 TreeNode buildTree(int[] inorder, int[] postorder) {
if(postorder.length == 0 || inorder.length == 0){
return null;
}
return bulidHelper(inorder,0,inorder.length,postorder,0,postorder.length);
// 初始切割划分,原始中序和后序数组
}
private TreeNode bulidHelper(int[] inorder,int inorderStart,int inorderEnd,
int[] postorder,int postorderStart,int postorderEnd){
if(postorderStart == postorderEnd){
return null;
}
int rootVal = postorder[postorderEnd-1];
TreeNode root = new TreeNode(rootVal); // 根据后序遍历得到的根节点切割后形成新树
int middleIndex; // 根据后续遍历节点划分中序遍历元素,分出左右子树
for(middleIndex = inorderStart;middleIndex<inorderEnd;middleIndex++){
if(inorder[middleIndex]==rootVal){
break;
}
}
// 左子树区间范围左闭右开,右子树区间范围左开右闭
int leftInorderStart = inorderStart;
int leftInorderEnd = middleIndex;
int rightInorderStart = middleIndex+1;
int rightInordrEnd = inorderEnd;
int leftPostorderStart = postorderStart;
int leftPostorderEnd = postorderStart+(middleIndex-inorderStart);
int rightPostorderStart = leftPostorderEnd;
int rightPostorderEnd = postorderEnd-1;
root.left = bulidHelper(inorder,leftInorderStart,leftInorderEnd,postorder,leftPostorderStart,leftPostorderEnd);
root.right = bulidHelper(inorder,rightInorderStart,rightInordrEnd,postorder,rightPostorderStart,rightPostorderEnd);
return root;
}
}
4 105. 从前序与中序遍历序列构造二叉树
题目: 给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
和inorder
均 无重复 元素inorder
均出现在preorder
preorder
保证 为二叉树的前序遍历序列inorder
保证 为二叉树的中序遍历序列
思路:本题实质上与 106. 从中序与后序遍历序列构造二叉树 一致,区别在于采用前序遍历时,从头至尾依次为根节点、左子树、右子树,结合与中序遍历使用。
注意:前序遍历在划分新的两个前序遍历表时,右子树的区间范围可从右向左,根据右区间边界和右子树中序遍历元素个数生成。
Java实现
/**
* 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 TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0 || inorder.length ==0){
return null;
}
return buildHelper(inorder,0,inorder.length,preorder,0,preorder.length);
}
private TreeNode buildHelper(int[] inorder,int inorderStart,int inorderEnd,
int[] preorder,int preorderStart,int preorderEnd){
if(preorderStart == preorderEnd){
return null;
}
int rootValue = preorder[preorderStart];
TreeNode root = new TreeNode(rootValue);
int middleIndex;
for(middleIndex=inorderStart;middleIndex<inorderEnd;middleIndex++){
if(inorder[middleIndex] == rootValue){
break;
}
}
int leftInorderStart = inorderStart;
int leftInorderEnd = middleIndex;
int rightInorderStart = middleIndex+1;
int rightInorderEnd = inorderEnd;
int leftPreorderStart = preorderStart+1;
int leftPreorderEnd = leftPreorderStart+(middleIndex-leftInorderStart);
int rightPreorderEnd = preorderEnd;
int rightPreorderStart = rightPreorderEnd-(rightInorderEnd-rightInorderStart);
root.left = buildHelper(inorder,leftInorderStart,leftInorderEnd,preorder,leftPreorderStart,leftPreorderEnd);
root.right = buildHelper(inorder,rightInorderStart,rightInorderEnd,preorder,rightPreorderStart,rightPreorderEnd);
return root;
}
}