513.找树左下角的值
参考文章:代码随想录
参考视频:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值_哔哩哔哩_bilibili
解题思路:
解法1:递归
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
public int findBottomLeftValue(TreeNode root) {
find(root, 0);
return result;
}
public void find(TreeNode node, int depth) {
if (node.left == null && node.right == null) {
if (depth > maxDept) {
maxDept = depth;
result = node.val;
}
}
if (node.left != null) {
depth++;
find(node.left, depth);
depth--;
}
if (node.right != null) {
depth++;
find(node.right, depth);
depth--;
}
}
解法2:迭代
利用层序遍历,创建一个队列来存放二叉树的元素,而每次队列的第一个值即为该层最左边的元素,所以最后一层的队列第一个元素即为树左下角的值。
public int findBottomLeftValue1(TreeNode root) {
int res = 0;
if (root == null) return res;
Deque<TreeNode> deque = new LinkedList<>();
deque.offer(root);
while (!deque.isEmpty()) {
int size = deque.size();
for (int i = 0; i < size; i++) {
TreeNode node = deque.peek();
deque.poll();
if (i == 0) res = node.val;
if (node.left != null) {
deque.offer(node.left);
}
if (node.right != null) {
deque.offer(node.right);
}
}
}
return res;
}
112. 路径总和
参考文章:代码随想录
参考视频:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和_哔哩哔哩_bilibili
解题思路:
利用递归法,遍历到的节点的值进行累加,遇到叶子节点时,查看是否等于target值,若是返回true,注意回溯问题。
public class Leetcode112 {
int sum = 0;
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
if (root.left == null && root.right == null) {
if (sum + root.val == targetSum){
return true;
}
}
if (root.left != null) {
sum += root.val;
boolean left = hasPathSum(root.left, targetSum);
if(left) return true;
sum -= root.val;
}
if (root.right != null) {
sum += root.val;
boolean right = hasPathSum(root.right, targetSum);
if(right) return true;
sum -= root.val;
}
return false;
}
}
113.路径总和ii
解题思路:和上面路径总和的思路是一样的,不过是需要用数组去记录每一个等于target的路径数组。需要注意的是在java中添加路径到result中需要新建立一个数组集合去添加,不能拿原数组集添加,因为后续原数组集也会变动,从而改变了result的结果。同样也是注意回溯问题。
public class Leetcode113 {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
List<Integer> list = new LinkedList<>();
record(root, res, list, targetSum);
return res;
}
public void record(TreeNode node, List<List<Integer>> res, List<Integer> list, int targetSum) {
list.add(node.val);
if (node.left == null && node.right == null) {
targetSum -= node.val;
if (targetSum == 0) {
res.add(new ArrayList<>(list));
}
return;
}
if (node.left != null) {
targetSum -= node.val;
record(node.left, res, list, targetSum);
list.remove(list.size() - 1);
targetSum += node.val;
}
if (node.right != null) {
targetSum -= node.val;
record(node.right, res, list, targetSum);
list.remove(list.size() - 1);
targetSum += node.val;
}
}
}
106.从中序与后序遍历序列构造二叉树
参考文章:代码随想录
参考视频:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili
解题思路:
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。
流程如图:
那么代码应该怎么写呢?
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0) return null;
TreeNode root = new TreeNode(preorder[0]);
if (preorder.length == 1) return root;
int i = 0;
for (i = 0; i < inorder.length; i++) {
if (inorder[i] == root.val) break;
}
int[] preInorder = Arrays.copyOfRange(inorder, 0, i);
int[] postInorder = Arrays.copyOfRange(inorder, i + 1, inorder.length);
int[] prePreorder = Arrays.copyOfRange(preorder, 1, 1 + preInorder.length);
int[] postPreorder = Arrays.copyOfRange(preorder, 1 + preInorder.length, inorder.length);
root.left = buildTree(prePreorder, preInorder);
root.right = buildTree(postPreorder, postInorder);
return root;
}
105.从前序与中序遍历序列构造二叉树
解题思路:其实与上题的思路是完全一样的,总体是分成这几部:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取前序数组第一个元素作为节点元素。
-
第三步:找到前序数组第一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割前序数组,切成前序左数组和前序右数组
-
第六步:递归处理左区间和右区间
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (postorder.length == 0) return null;
TreeNode root = new TreeNode(postorder[postorder.length - 1]);
if (postorder.length == 1) return root;
int i;
for (i = 0; i < inorder.length; i++) {
if (inorder[i] == root.val) break;
}
int[] preInorder = Arrays.copyOfRange(inorder, 0, i);
int[] postInorder = Arrays.copyOfRange(inorder, i + 1, inorder.length);
int preSize = preInorder.length;
int[] prePostorder = Arrays.copyOfRange(postorder, 0, preSize);
int[] postPostorder = Arrays.copyOfRange(postorder, preSize, postorder.length - 1);
root.left = buildTree(preInorder, prePostorder);
root.right = buildTree(postInorder, postPostorder);
return root;
}