代码随想录第十八天| 513.找树左下角的值,112. 路径总和 113.路径总和ii,106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

 题目与题解

513.找树左下角的值

题目链接:513.找树左下角的值

代码随想录题解:513.找树左下角的值

视频讲解:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值_哔哩哔哩_bilibili

解题思路:

        这道题用迭代比较容易想。所谓树最底层最左边的叶子节点,就是树最深处从左往右数第一个叶子节点,那么就可以用层序遍历,每遍历到新的一层,就把第一个结点记录下来,直到没有更深的层,此时记录的最新结点就是最左下角的值。

class Solution {
    public int findBottomLeftValue(TreeNode root) {
		if (root == null) return 0;
		Queue<TreeNode> q = new LinkedList<>();
		q.add(root);
		int result = root.val;
		while (!q.isEmpty()) {
			int size = q.size();
			result = q.peek().val;
			for (int i = 0; i < size; i++) {
				TreeNode node = q.peek();
				if (node.left != null) q.add(node.left);
				if (node.right != null) q.add(node.right);
				q.poll();
			}
		}
		return result;
    }

}

看完代码随想录之后的想法 

        层序遍历一样,递归不是很好想,不仅要记录和更新每次递归的深度,还要用回溯,容易出错。可以后面学习。

// 递归法
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);
    }
}

遇到的困难

        回溯法还是不太懂。

112. 路径总和 113.路径总和ii

题目链接:112. 路径总和 113.路径总和ii

代码随想录题解:​​​​​​​112. 路径总和 113.路径总和ii

视频讲解:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和_哔哩哔哩_bilibili

解题思路:

        这里用递归比较好做,对于112,递归入参为根结点和targetSum,返回值是布尔值,表示当前路径之和是否符合要求,终止条件是当前结点是叶子结点。递归体为:如果当前结点是叶子结点,且其值等于入参的targetSum,则为true,如果其值与入参不相等,则为false;对于非叶子结点,调用递归函数,入参为其左叶子或右叶子,targetSum的值为targetSum - root.val。最后主函数返回左子树或右子树是否存在符合要求的路径。

        

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
		if (root == null) return false;
		if (root.left == null && root.right == null) {
			return targetSum == root.val;
		}
		return hasPathSum(root.left, targetSum - root.val)
				|| hasPathSum(root.right, targetSum - root.val);
    }
}

        113就有点难,直接看答案了。 

看完代码随想录之后的想法 

        迭代不会,回溯也不是很会,先码一下,后面再看

class Solution {
	List<List<Integer>> result = new ArrayList<>();
	List<Integer> list = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
		if (root == null) return result;
		list.add(root.val);
		pathSum1(root, targetSum);
		return result;
    }


	public void pathSum1(TreeNode root, int targetSum) {
		if (root.left == null && root.right == null && targetSum == root.val) {
			result.add(list);
			return;
		}
		if (root.left == null && root.right == null) {
			return;
		}
		if (root.left != null) {
			list.add(root.left.val);
			targetSum -= root.left.val;
			pathSum1(root.left, targetSum);
			targetSum += root.left.val;
			list.remove(list.size() - 1);
		}
		if (root.right != null) {
			list.add(root.right.val);
			targetSum -= root.right.val;
			pathSum1(root.right, targetSum);
			targetSum += root.right.val;
			list.remove(list.size() - 1);
		}
	}
}

遇到的困难

        回溯有点难想,有点费解

106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

题目链接:106.从中序与后序遍历序列构造二叉树105.从前序与中序遍历序列构造二叉树

代码随想录题解:​​​​​​​106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

视频讲解:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili

解题思路:

        当年算法课学过如何手工从中序和后序或者中序和前序构造二叉树,这里就是把过程具象化了,第一次写,磕磕绊绊的,但是写出来了。

        首先,对于后序遍历,其最后的元素就是根结点,与之对应的前序遍历的第一个结点就是根结点。已知根结点后,就可以从中序遍历中找到根结点所在位置index,那么在中序遍历中,根结点左边的都是左子树的值,右边都是右子树的值,这样就可以获得左右子树具体各含多少个元素。再回到后序遍历中,此时只需要再递归的调用该函数,将中序遍历中左子树的元素构成数组,后序遍历中从头取出同样多的元素构成数组,放入该函数,返回的就是左子树的根结点;相对应的,将中序遍历中位置大于index右子树的元素构成数组,后序遍历中从index到倒数第二个元素构成数组,放入该函数,返回的就是右子树的根结点。

        因此该递归函数的入参为需要构成数的后序/前序遍历和中序遍历数组,返回值为构造的成功的根结点,终止条件为如果数组只含一个元素,直接返回用它构造的根节点;否则根据其根结点所在位置,递归的调用该函数,分别构造根节点的左右结点。

后序+中序

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
		if (inorder.length == 1) return new TreeNode(inorder[0]);
		int val = postorder[postorder.length - 1];
		TreeNode root = new TreeNode(val);
		int indexRoot = 0;
		for (int i = 0; i < inorder.length; i++) {
			if (inorder[i] == val) {
				indexRoot = i;
				break;
			}
		}
		if (indexRoot == 0) {
			root.right = buildTree(Arrays.copyOfRange(inorder, 1, inorder.length),
									Arrays.copyOfRange(postorder, 0, postorder.length - 1));
		} else if (indexRoot == inorder.length - 1) {
			root.left = buildTree(Arrays.copyOfRange(inorder, 0, inorder.length - 1),
					Arrays.copyOfRange(postorder, 0, inorder.length - 1));
		} else {
			root.left = buildTree(Arrays.copyOfRange(inorder, 0, indexRoot),
					Arrays.copyOfRange(postorder, 0, indexRoot));
			root.right = buildTree(Arrays.copyOfRange(inorder, indexRoot + 1, inorder.length),
					Arrays.copyOfRange(postorder, indexRoot, postorder.length - 1));
		}
		return root;
    }

}

前序+中序

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
		if (inorder.length == 1) return new TreeNode(inorder[0]);
		int val = preorder[0];
		TreeNode root = new TreeNode(val);
		int indexRoot = 0;
		for (int i = 0; i < inorder.length; i++) {
			if (inorder[i] == val) {
				indexRoot = i;
				break;
			}
		}
		if (indexRoot == 0) {
			root.right = buildTree(Arrays.copyOfRange(preorder, 1, inorder.length),
					Arrays.copyOfRange(inorder, 1, inorder.length));
		} else if (indexRoot == inorder.length - 1) {
			root.left = buildTree(Arrays.copyOfRange(preorder, 1, inorder.length),
					Arrays.copyOfRange(inorder, 0, inorder.length - 1));
		} else {
			root.left = buildTree(Arrays.copyOfRange(preorder, 1, indexRoot + 1),
					Arrays.copyOfRange(inorder, 0, indexRoot));
			root.right = buildTree(Arrays.copyOfRange(preorder, indexRoot + 1, inorder.length),
					Arrays.copyOfRange(inorder, indexRoot + 1, inorder.length));
		}
		return root;
    }
}

看完代码随想录之后的想法 

        其实写下来思路还是清晰的,就是入参的时候下标究竟是什么样的,得用几个例子好好写一写,才能清楚。

        思路差不多,因为java不支持传地址,生成新的数组比较麻烦,所以随想录用了一个新的递归方法,包含了中序以及前序/后序遍历start和end的下标,会好写很多。Arrays.copyOfRange方法有限制,因为输入的左右边界是左闭右开的,所以得保证输入的边界中一定有数,否则会出错,因此在仅有左子树或仅有右子树时,还需要额外的处理。        

今日收获

        二叉树涉及到回溯的非常难,可能现在也没有耐心好好学,后面复习再看。

        补写出来了根据前序/后序+中序遍历的方式构造二叉树,很有成就感。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值