513.找树左下角的值
思路:用前序遍历(因为先遍历左边),并且遍历的时候记录节点的深度。每次深度更新的时候去记录下深度变大时节点的数值。由于先遍历左节点,所以最后得到的值就是树的最后一行最左边的值
总结:
迭代法更优:
层序遍历更直观,最后一层的第一个就是返回值。记录每层的第一个数值即可
遍历法:
前中后序都可以,都是优先遍历左节点
减少赋值的次数:只在叶子节点,并且最大深度更新的时候赋值。由于优先遍历左节点,所以最大深度更新的时候就是最左侧的节点。
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;
}
}
findLeftValue(root.left,deep + 1);
findLeftValue(root.right,deep + 1);
}
}
//迭代法
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode poll = queue.poll();
if (i == 0) {
res = poll.val;
}
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
}
return res;
}
}
112. 路径总和
思路:回溯来来追溯路径和,满足条件就返回true
总结:
没有中的逻辑,所以前中后序都一样,(其实前序位置更改变量,后续位置做回溯)
什么时候需要返回值
再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
引用自:代码随想录
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况
113题中不要跟112的类型搞混,113需要遍历整个二叉树,不能提前返回
//112
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null)return false;
if(root.left==null&&root.right==null&&targetSum==root.val)return true;
targetSum-=root.val;
boolean right = hasPathSum(root.right,targetSum);
boolean left = hasPathSum(root.left,targetSum);
// targetSum+=root.val;
return right||left;
}
}
//迭代
class solution {
public boolean haspathsum(treenode root, int targetsum) {
if(root == null) return false;
stack<treenode> stack1 = new stack<>();
stack<integer> stack2 = new stack<>();
stack1.push(root);
stack2.push(root.val);
while(!stack1.isempty()) {
int size = stack1.size();
for(int i = 0; i < size; i++) {
treenode node = stack1.pop();
int sum = stack2.pop();
// 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
if(node.left == null && node.right == null && sum == targetsum) {
return true;
}
// 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if(node.right != null){
stack1.push(node.right);
stack2.push(sum + node.right.val);
}
// 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if(node.left != null) {
stack1.push(node.left);
stack2.push(sum + node.left.val);
}
}
}
return false;
}
}
113
class Solution {
List<List<Integer>> res;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
res = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
traverse(root,path,targetSum);
return res;
}
public void traverse(TreeNode root,LinkedList<Integer> path, int targetSum) {
if(root==null)return;
targetSum-=root.val;
path.addLast(root.val);
if(root.left==null&&root.right==null&&targetSum==0){
res.add(new LinkedList<>(path));
// return;此处不能有return否则后面的回溯无法完成,要搜索整颗二叉树
}
traverse(root.right,path,targetSum);
traverse(root.left,path,targetSum);
path.removeLast();
// targetSum+=root.val;
}
}
//迭代
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> result = new ArrayList<>();
Stack<TreeNode> nodeStack = new Stack<>();
Stack<Integer> sumStack = new Stack<>();
Stack<ArrayList<Integer>> pathStack = new Stack<>();
if(root == null)
return result;
nodeStack.add(root);
sumStack.add(root.val);
pathStack.add(new ArrayList<>());
while(!nodeStack.isEmpty()){
TreeNode currNode = nodeStack.peek();
int currSum = sumStack.pop();
ArrayList<Integer> currPath = pathStack.pop();
if(currNode != null){
nodeStack.pop();
nodeStack.add(currNode);
nodeStack.add(null);
sumStack.add(currSum);
currPath.add(currNode.val);
pathStack.add(new ArrayList(currPath));
if(currNode.right != null){
nodeStack.add(currNode.right);
sumStack.add(currSum + currNode.right.val);
pathStack.add(new ArrayList(currPath));
}
if(currNode.left != null){
nodeStack.add(currNode.left);
sumStack.add(currSum + currNode.left.val);
pathStack.add(new ArrayList(currPath));
}
}else{
nodeStack.pop();
TreeNode temp = nodeStack.pop();
if(temp.left == null && temp.right == null && currSum == targetSum)
result.add(new ArrayList(currPath));
}
}
return result;
}
}
106.从中序与后序遍历序列构造二叉树
数组的区间定义一定要统一
写代码的时候可以把分割的数组打印出来,更好debug
前序后续无法确定唯一二叉树。找不到分割点e.g
学会打日志来调试(如何打日志有时候也是个技术活),不要脑动模拟,脑动模拟很容易越想越乱
1.判断后序数组是否为空,为空返回null节点
2.不为空的话,在后续遍历中找到末尾的根节点
3.依靠根节点,找到根节点在中序数组中的位置
4.切割中序数组,切成中序左,和中序右 (一定先切中序)
5.依据中序切割切割后序数组,切成后序左,和后序右
6.递归处理左区间右区间