代码随想录算法训练营第18天 | 513. 找树左下角的值,112. 路径总和,106.从中序与后序遍历序列构造二叉树,105.从前序与中序遍历序列构造二叉树
513. 找树左下角的值
- 用层序遍历的话 每一层都把最左边节点的值给到一个变量 那么他每次都会更新 最后输出为最后一层的值
层序遍历
class Solution {
public int findBottomLeftValue(TreeNode root) {
Deque<TreeNode> que = new LinkedList<>();
int leftval = 0;
if(root!=null) que.addLast(root);
while(!que.isEmpty()){
int size = que.size();
int size2 = size;
while(size!=0){
TreeNode node = que.pollFirst();
if(size==size2){
leftval = node.val;
}
if(node.left!=null) que.addLast(node.left);
if(node.right!=null) que.addLast(node.right);
size--;
}
}
return leftval;
}
}
递归法
- 要求最后一行最靠左节点的值 只需要先向左遍历到最后一行即为结果
- 此题也没有中的操作 所以只需要先向左遍历再向右遍历
- 如何判断当前深度为最后一行 即每次遇到叶节点就判断 是否大于当前记录的最大深度 若不是就更新最大深度
- 回溯 就是当左边遍历到底了 想回去继续遍历右边 就需要每次递归完一次就往回退一格 往上回去
class Solution {
int maxdepth = -1;
int res = 0;
public int findBottomLeftValue(TreeNode root) {
traversal(root,0);
return res;
}
public void traversal(TreeNode node,int depth){
if(node.left==null && node.right==null){
if(depth>maxdepth){
res = node.val;
maxdepth = depth;
}
}
if(node.left!=null){
depth++;
traversal(node.left,depth);
depth--;
}
if(node.right!=null){
depth++;
traversal(node.right,depth);
depth--;
}
}
}
112. 路径总和
- 终止条件为当 count减到0就 return ture 否则return false
- 需要首先减掉一次VAL 有可能root只有一个节点
- 接下来向左右遍历 如果下面的结果返回为ture 那么继续往上返回ture 往上面传递
- 然后回溯 即把count值加回来
- 注意传入 递归函数的参数很重要 假如传入的是 targetsum 那么就需要另一个变量来计数 然后就需要回溯 因为这个变量下去之后他的值变了
- 但是假如传入参数 就为count 那么就不需要回溯 因为每次递归 的count都是没变的 返回来上层的count
回溯隐藏
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null) return false;
return pathsum(root,targetSum);
}
public boolean pathsum(TreeNode node, int count){
count-=node.val;
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){
if(pathsum(node.left,count)){
return true;
}
}
if(node.right!=null){
if(pathsum(node.right,count)==true){
return true;
}
}
return false;
}
}
回溯不隐藏
- 设置全局变量
class Solution {
boolean flag = false;
int count = 0;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null) return false;
pathsum(root,targetSum);
return flag;
}
public void pathsum(TreeNode node, int targetSum){
count+=node.val;
if(node.left==null && node.right==null && count==targetSum){
flag = true;
return;
}
if(node.left!=null){
pathsum(node.left,targetSum);
}
if(node.right!=null){
pathsum(node.right,targetSum);
}
count-=node.val;
}
}
113. 路径总和 II
- 路径总和ii要遍历整个树,找到所有路径,所以递归函数不要返回值
- 每次判断 targetSum-node.val是否为0 若不是 就继续向下面递归
- 向下递归时 传入的参数可以为 targetSum-node.val 这样递归完返回出来接下去的时候 targetSum不会改变
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> arr = 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){
arr.add(node.val);
if(node.left==null && node.right==null){
if(targetSum-node.val==0){
res.add(new ArrayList<>(arr));
}
return;
}
if(node.left!=null){
getpath(node.left,targetSum-node.val);
arr.remove(arr.size()-1);
}
if(node.right!=null){
getpath(node.right,targetSum-node.val);
arr.remove(arr.size()-1);
}
}
}
106.从中序与后序遍历序列构造二叉树
- 后序最后一个元素是根节点的值 找到根节点后 在中序中就可以知道左子树的长度 从而也知道右子树
- 然后对两个数组都进行切割 向左右递归
用map存inorder索引做法
class Solution {
Map<Integer,Integer> map = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return createTree(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode createTree(int[] inorder,int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd){
if(inBegin>=inEnd || postBegin>=postEnd){
return null;
}
TreeNode root = new TreeNode(postorder[postEnd-1]);
int rootIndex = map.get(root.val);
int leftLen = rootIndex-inBegin;
root.left = createTree(inorder,inBegin,rootIndex,postorder,postBegin,postBegin+leftLen);
root.right = createTree(inorder,rootIndex+1,inEnd,postorder,postBegin+leftLen,postEnd-1);
return root;
}
}
直接用循环遍历来找rootIndex
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return createTree(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode createTree(int[] inorder,int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd){
if(inBegin>=inEnd || postBegin>=postEnd){
return null;
}
TreeNode root = new TreeNode(postorder[postEnd-1]);
int rootIndex=inBegin;
for(;rootIndex<inEnd;rootIndex++){
if(inorder[rootIndex]==root.val){
break;
}
}
int leftLen = rootIndex-inBegin;
root.left = createTree(inorder,inBegin,rootIndex,postorder,postBegin,postBegin+leftLen);
root.right = createTree(inorder,rootIndex+1,inEnd,postorder,postBegin+leftLen,postEnd-1);
return root;
}
}
105.从前序与中序遍历序列构造二叉树
- 原理同上一题一样 即利用前序数组找到root 然后利用中序数组找到左右子树 递归下去
class Solution {
Map<Integer,Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for(int i = 0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return createTree(preorder,0,preorder.length,inorder,0,inorder.length);
}
public TreeNode createTree(int[] preorder,int preBegin,int preEnd,int[] inorder,int inBegin, int inEnd){
if(preBegin>=preEnd || inBegin>=inEnd){
return null;
}
TreeNode root = new TreeNode(preorder[preBegin]);
int rootIndex = map.get(root.val);
int leftlen = rootIndex - inBegin;
root.left = createTree(preorder,preBegin+1,preBegin+leftlen+1,inorder,inBegin,rootIndex);
root.right = createTree(preorder,preBegin+leftlen+1,preEnd,inorder,rootIndex+1,inEnd);
return root;
}
}