力扣刷题调试小技巧:导入import java.util.*;包,使用System.out.println(n);进行日志输出,可以帮助调试代码
递归法:首先明确题意,左下角的值,并不是要招深度最深的左叶子节点,若最深的节点为右叶子节点也是符合题意的。所以这题的关键就在于找出深度最深的叶子节点。这里前中后序都可以解决,因为不需要处理中间节点。
终止条件:遍历到叶子节点,将当前深度赋值给深度变量,同时将叶子节点的值赋给结果变量,当遍历完所有叶子节点后,将取得最大深度的叶子节点的值,将结果变量返回即可。
单层处理逻辑:每往下遍历一个节点,深度加一,递归返回后,深度减一,回溯到上一个节点,找新的左子树或右子树进行递归遍历。
//这里最左边的值不是左子树,只要是最下面的最左边的就行,所以深度最大的右叶子节点也是
class Solution {
private int maxdepth=-1;
private int result=0;
public int findBottomLeftValue(TreeNode root) {
result=root.val;
getvalue(root,1);
return result;
}
public void getvalue(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++;
getvalue(node.left,depth);
depth--;//回溯
}
if(node.right!=null){
depth++;
getvalue(node.right,depth);
depth--;
}
}
}
层序遍历法:层序遍历非常直观,丝滑解题
class Solution {
public int findBottomLeftValue(TreeNode root) {
if(root==null){
return 0;
}
ArrayDeque<TreeNode> queue=new ArrayDeque();
queue.addLast(root);
int res=0;
while(!queue.isEmpty()){
int size=queue.size();
for(int i=0;i<size;i++){
TreeNode node=queue.poll();
if(i==0) res=node.val;
if(node.left!=null){
queue.addLast(node.left);
}
if(node.right!=null){
queue.addLast(node.right);
}
}
}
return res;
}
}
该题和昨天的求二叉树所有路径的题解法基本一致,采用前序遍历,将中间节点先加入路径数组中,再遍历左子树和右子树,当遍历到叶子节点后,将路径之后存到结果数组中。
终止条件:遍历到叶子节点,保存路径之和
单层处理逻辑:还是递归加回溯,沿着左子树或者右子树遍历完一条路径后,递归返回,路径变量回溯,重新遍历右子树或者左子树。
class Solution {
private int x=0;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null){
return false;
}
List<Integer> path=new ArrayList();
gettarget(root,targetSum,path);
if(x==1){
return true;
}else{
return false;
}
}
public void gettarget(TreeNode node,int targetSum,List<Integer> path){
path.add(node.val);
if(node.left==null&&node.right==null){
int result=0;
for(int i=0;i<path.size();i++){
result+=path.get(i);
}
if(result==targetSum) x=1;
}
if(node.left!=null){
gettarget(node.left,targetSum,path);
path.remove(path.size()-1);
}
if(node.right!=null){
gettarget(node.right,targetSum,path);
path.remove(path.size()-1);
}
}
}
该题相当于是上一题的拓展,其实解法一样。只不过这里有个需要注意的点,就是将一维数组存入二维数组中时,不能直接存,因为直接存,存的相当于是一维数组的指针,一维数组在后续回溯发生变化时,二维数组也会变化,导致错误。
class Solution {
List<Integer> path=new ArrayList();
List<List<Integer>> res=new ArrayList();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if(root==null){
return res;
}
getpath(root,targetSum);
return res;
}
public void getpath(TreeNode node,int targetSum){
path.add(node.val);
if(node.left==null&&node.right==null){
int sum=0;
for(int i=0;i<path.size();i++){
sum+=path.get(i);
}
if(sum==targetSum){
res.add(new ArrayList(path));
}
return;
}
if(node.left!=null){
getpath(node.left,targetSum);
path.remove(path.size()-1);
}
if(node.right!=null){
getpath(node.right,targetSum);
path.remove(path.size()-1);
}
}
}
将一维数组加入二维数组时要特别注意, List<Integer> path=new ArrayList(); List<List<Integer>> res=new ArrayList();不能直接res.add((path);因为res会随着回溯path的元素改变导致res中的元素改变,需要新new一个数组放入其中,因为数组是引用数据类型,二维数组的元素相当于一个指针指向path,改变path后res也跟着变化。
这一题就复杂一些,有边界情况需要处理。这一题的关键就是后序遍历数组的最后一位是根节点,找到根节点后,可以在中序遍历数组中找到根节点对应的索引,可以将中序遍历数组划分成根节点的左右子区间。根据中序遍历数组划分出的左子区间大小可以在后序遍历数组中划分出对应的左右子区间。接着就是利用左右子区间进行递归获得左右子区间中的根节点,也就是二叉树根节点的左右子节点。
终止条件:左右子区间的区间不合法
单层处理逻辑:划分左右子区间,获得区间起始点和终点,作为参数继续参与递归。
class Solution {
Map<Integer,Integer>map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map=new HashMap();//使用map保存中序遍历中元素及其对应索引,以便在后序遍历中分割
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
TreeNode root=getroot(inorder,0,inorder.length,postorder,0,postorder.length);
return root;
}
public TreeNode getroot(int[] inorder,int inbegin,int inend,int[] postorder,int pobegin,int poend){
if(inbegin>=inend||pobegin>=poend){ //区间左闭右开
return null;
}
//首先从后序遍历中的根节点找到中序遍历中根节点对于的索引位置
int rootindex=map.get(postorder[poend-1]);
TreeNode root=new TreeNode(postorder[poend-1]);
//根据索引分割后序遍历中的左后序遍历和右后序遍历
//保存中序左子树个数,用来分割后序遍历左子树
int lenOfleft=rootindex-inbegin;
//递归处理左区间
root.left=getroot(inorder,inbegin,rootindex,postorder,pobegin,pobegin+lenOfleft);
//递归处理右区间
root.right=getroot(inorder,rootindex+1,inend,postorder,pobegin+lenOfleft,poend-1);
return root;
}
}