摘要
本文主要介绍了LeetCode二叉树的几个题目,包括513.找树左下角的值、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树。
1、513.找树左下角的值
1.1 迭代法
- 层序遍历,遍历至结束,队列ArrayDeque的第一个元素值即为最底层最左边节点的值
public int findBottomLeftValue(TreeNode root) {
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
int res = root.val;
while(!deque.isEmpty()) {
int size = deque.size();
for(int i=0; i<size; i++) {
TreeNode node = 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;
}
1.2 递归法
-
递归遍历,找到所有的叶子节点,将当前叶子节点的深度与最大深度比较
-
如果叶子节点的深度大于最大深度,设置最大深度最左节点的数值为该叶子节点的值,并更新最大深度
- maxDept:记录最大深度
- res:最大深度最左节点的数值
private int maxDept;
private int res;
public int findBottomLeftValue(TreeNode root) {
maxDept = 0;
res = root.val;
findLeftValue(root, 0);
return res;
}
private void findLeftValue(TreeNode root, int dept) {
if(root == null) {
return;
}
if(root.left == null && root.right == null) {
if(dept > maxDept) {
maxDept = dept;
res = root.val;
}
return;
}
findLeftValue(root.left, dept+1);
findLeftValue(root.right, dept+1);
}
2、112. 路径总和
2.1 思路
- 递归+回溯
- 递归结束:如果root为空返回false,定义
newTarget=targetSum-root.val,如果节点是叶子节点(root.left == null && root.right == null)并且newTarget=0返回true - 递归过程:每次进入递归设置
targetSum=newTarget,左右子树有一个存在就返回true
2.2 代码
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) {
return false;
}
int newTarget = targetSum - root.val;
if(root.left == null && root.right == null && newTarget == 0) {
return true;
}
return hasPathSum(root.left, newTarget) || hasPathSum(root.right, newTarget);
}
3、113.路径总和ii
3.1 思路
- 递归+回溯
- 判断满足条件的叶子节点的思路同112. 路径总和,如果满足条件将LinkedList加入到返回结果中
- 递归遍历中,将当前节点的值加入到LinkedList中,遍历左右子树,遍历结束从LinkedList删除值
3.2 代码
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> list = new ArrayList<>();
LinkedList<Integer> linkedList = new LinkedList<>();
doPathSum(root, targetSum, list, linkedList);
return list;
}
public void doPathSum(TreeNode root, int targetSum,
List<List<Integer>> list, LinkedList<Integer> linkedList) {
if(root == null) {
return;
}
linkedList.add(root.val);
int newTarget = targetSum - root.val;
if(root.left == null && root.right == null && newTarget == 0) {
list.add(new ArrayList<>(linkedList));
}
doPathSum(root.left, newTarget, list, linkedList);
doPathSum(root.right, newTarget, list, linkedList);
linkedList.removeLast();
}
4、106.从中序与后序遍历序列构造二叉树
4.1 思路
-
首先将后序数组中的元素加入到map中,key为元素值,value为数组下标
-
后序遍历数组最后一个元素,就是当前的中间节点
-
找到后序数组最后一个元素在中序数组的位置,作为切割点,即通过map找到在中序数组的位置inIdx
-
定义len为左子树的大小inIdx-inStart,因为中序数组大小一定是和后序数组的大小相同的,所以有:
- 左子树部分:中序数组
[inStart, inIdx-1],后序数组[postStart, postStart+len-1] - 右子树部分:中序数组
[inIdx+1, inEnd],后序数组[postStart+len, postEnd-1]
- 左子树部分:中序数组
4.2 代码
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 doBuildTree(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public TreeNode doBuildTree(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if(postStart > postEnd || inStart > inEnd) {
return null;
}
int inIdx = map.get(postorder[postEnd]);
int len = inIdx - inStart; // 左子树个数
TreeNode root = new TreeNode(postorder[postEnd]);
root.left = doBuildTree(inorder, inStart, inIdx-1, postorder, postStart, postStart+len-1);
root.right = doBuildTree(inorder, inIdx+1, inEnd, postorder, postStart+len, postEnd-1);
return root;
}
5、105.从前序与中序遍历序列构造二叉树
5.1 思路
-
思路同106. 从中序与后序遍历序列构造二叉树
-
两个关键点:
- 前序遍历的第一个元素在中序遍历的位置即为切割点
- 前序遍历和中序遍历数组大小是相同的
5.2 代码
public TreeNode buildTree(int[] preorder, int[] inorder) {
for(int i=0; i<inorder.length; i++) {
map.put(inorder[i], i);
}
// 左闭右闭
return doBuildTree(inorder, 0, inorder.length-1, preorder, 0, preorder.length-1);
}
public TreeNode doBuildTree(int[] inorder, int inStart, int inEnd, int[] preorder,
int preStart, int preEnd) {
if(inStart > inEnd || preStart > preEnd) {
return null;
}
int idx = map.get(preorder[preStart]);
int len = idx - inStart;
TreeNode node = new TreeNode(preorder[preStart]);
node.left = doBuildTree(inorder, inStart, idx-1, preorder, preStart+1, preStart+len);
node.right = doBuildTree(inorder, idx+1, inEnd, preorder, preStart+len+1, preEnd);
return node;
}