用队列储存每一层的节点数,对每一层的节点数循环,加载对应的叶子结点。
在每一个层时,将这一层的第一个节点的值存起来,就是左节点的值。一直更新就是最后一层。
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue=new LinkedList<>();
int res=0;
if(root!=null){
queue.add(root);
}
while(!queue.isEmpty()){
int len=queue.size();
for(int i=0;i<len;i++){
TreeNode node=queue.poll();
if(i==0){
res=node.val;
}
if(node.left!=null)queue.add(node.left);
if(node.right!=null)queue.add(node.right);
}
}
return res;
}
}
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
递归三要素:
参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。
本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度
class Solution {
int maxDeep=-1;
int res;
public int findBottomLeftValue(TreeNode root) {
left(root,0);
return res;
}
public void left(TreeNode root,int deep){
if(root.left==null&&root.right==null){
if(deep>maxDeep){
maxDeep=deep;
res=root.val;
}
// deep=root.val;
// res=res>deep?res:deep;
}
if(root.left!=null){
left(root.left,deep+1);
}
if(root.right!=null){
left(root.right,deep+1);
}
}
}
首先计数器如何统计这一条路径的和呢?
不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。
如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。
如果遍历到了叶子节点,count不为0,就是没找到。
递归终止条件代码如下:count-当前节点数为0
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
// List path = new ArrayList<>();
// int res=0;
if(root==null){
return false;
}
return traversal(root,targetSum);
}
private boolean traversal(TreeNode node,int count){
if(node.left==null&&node.right==null){
if(count-node.val==0){
return true;
}else{
return false;
}
}
if(node.left!=null){
if(traversal(node.left,count-node.val)){
return true;
}
}
if(node.right!=null){
if(traversal(node.right,count-node.val)){
return true;
}
}
return false;
}
}
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
// List path = new ArrayList<>();
// int res=0;
if(root==null){
return false;
}
if(root.left==null&&root.right==null&root.val==targetSum){
return true;
}
if(root.left!=null){
if(hasPathSum(root.left,targetSum-root.val))return true;
}
if(root.right!=null){
if(hasPathSum(root.right,targetSum-root.val))return true;
}
return false;
}
}
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
// List path = new ArrayList<>();
// int res=0;
if(root==null){
return false;
}
if(root.left==null&&root.right==null&root.val==targetSum){
return true;
}
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
一个储存每一个路径的节点,当遇到叶子结点时,根据target是否等于路径和判断res是否要储存。
且每一次都要进行回溯,
class Solution {
List<List<Integer>> res;
List<Integer> path;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
res = new ArrayList<>();
path = new LinkedList<>();
// if(root == null) return res; // 非空判断
travesal(root,targetSum);
return res;
}
public void travesal(TreeNode root,int targetSum){
if(root==null)return;
path.add(root.val);
if(root.left==null&&root.right==null&&root.val==targetSum){
// 路径和满足条件,储存路径
res.add(new ArrayList<>(path));
}
// if(root.left!=null){
// travesal(root.left,targetSum-root.val);
// // 怎么回溯
// // path.removeLast();
// }
// if(root.right!=null){
// travesal(root.right,targetSum-root.val);
// // path.removeLast();
// }
travesal(root.left,targetSum-root.val);
travesal(root.right,targetSum-root.val);
path.removeLast();// 回溯这一次的节点
}
}
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
不难写出如下代码:(先把框架写出来)
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;
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 第五步:切割后序数组,得到 后序左数组和后序右数组
// 第六步
root->left = traversal(中序左数组, 后序左数组);
root->right = traversal(中序右数组, 后序右数组);
return root;
}
class Solution {
Map<Integer,Integer>map;// 方便根据数值查找位置
public TreeNode buildTree(int[] inorder, int[] postorder) {
map=new HashMap<>();
// 储存中序序列的数值对应的位置
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return findNode(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode findNode(
int[] inorder,int inBegin,int inEnd,int[] postorder,int pBegin,int pEnd){
// 不满足左闭右开,说明没有元素,要返回
if(inBegin>=inEnd ||pBegin>=pEnd){
return null;
}
// 这里代码还没写
// if(postorder.length==0)return null;
// 根据postorder的数值找到中序序列分割点的index
int rootIndex=map.get(postorder[pEnd-1]);
// 构造节点
TreeNode root = new TreeNode(inorder[rootIndex]);
// 开始分割
// 中序
// 保存中序左子树个数,
int lenofleft = rootIndex-inBegin;
root.left=findNode(inorder,inBegin,rootIndex,postorder,pBegin,pBegin+lenofleft);
root.right=findNode(inorder,rootIndex+1,inEnd,postorder,pBegin+lenofleft,pEnd-1);
return root;
}
}
和前一题相同
/**
* 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 {
Map<Integer,Integer>map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
map= new HashMap<>();
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return Tree(preorder,0,preorder.length,inorder,0,inorder.length);
}
public TreeNode Tree(int[] preorder, int preBegin,int preEnd,int[] inorder,int inBegin,int inEnd) {
if(preBegin>=preEnd||inBegin>=inEnd){
return null;
}
int rootIndex=map.get(preorder[preBegin]);
TreeNode root=new TreeNode(inorder[rootIndex]);
int lenofleft=rootIndex-inBegin;
root.left=Tree(preorder,preBegin+1,lenofleft+preBegin+1,inorder,inBegin,rootIndex);
root.right=Tree(preorder,preBegin+lenofleft+1,preEnd,inorder,rootIndex+1,inEnd);
return root;
}
}