513.寻找树左下角的值
思路:通过层序遍历比较简单,但是层序遍历的时候需要从右到左来遍历,最后一个遍历的节点就是树左下角的值。递归遍历也可以,因为不需要处理中间节点,所以只需要保证先左后右的顺序就好,可以看作前序遍历。每次遍历到叶子节点,记录深度,如果深度比当前深度大,更新结果。
层序遍历实现
class Solution {
public int findBottomLeftValue(TreeNode root) { // 层序遍历
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
int size = 0;
while (!que.isEmpty()) {
size = que.size();
while (size-- > 0) {
TreeNode node = que.poll();
if (node.right != null) {
que.add(node.right);
}
if (node.left != null) {
que.add(node.left);
}
if (que.isEmpty()) {
return node.val;
}
}
}
return -1;
}
}
递归遍历实现
class Solution {
private int maxDeep = -1;
private int ans = 0;
public int findBottomLeftValue(TreeNode root) { // 前序递归遍历
ans = root.val;
getLeftVal(root, 0);
return ans;
}
public void getLeftVal(TreeNode node, int deep) {
if (node == null) return;
if (node.left == null && node.right == null) { // 若为叶子节点
if (deep > maxDeep) { // 深度比当前最大深度大
ans = node.val; // 更新结果
maxDeep = deep;
}
}
getLeftVal(node.left, deep + 1);
getLeftVal(node.right, deep + 1);
}
}
112.路经总和
思路:采用后序递归遍历,当遍历到叶子节点的时候判断是否符合条件,符合条件返回true,不符合条件返回false,只要有一个孩子是true就是true。(注意回溯的过程。)
class Solution {
private int count = 0;
public boolean hasPathSum(TreeNode root, int targetSum) { // 后序递归遍历
if (root == null) return false;
count += root.val;
if (root.left == null && root.right == null && count == targetSum) {
return true;
}
boolean left = false;
if (root.left != null) {
left = hasPathSum(root.left, targetSum);
count -= root.left.val;
}
boolean right = false;
if (root.right != null) {
right = hasPathSum(root.right, targetSum);
count -= root.right.val;
}
return left || right;
}
}
113.路径总和II
思路:递归遍历,没有处理中节点的操作,(可以看成前序遍历)定义数组来记录路径,每当遍历到叶子节点的时候判断是否符合条件,符合条件就将路径加入到结果中。(注意回溯过程)
class Solution {
private List<List<Integer>> ans; // 结果
private List<Integer> path = new ArrayList<>(); // 记录路径
public List<List<Integer>> pathSum(TreeNode root, int targetSum) { // 递归遍历
ans = new ArrayList<>();
if (root == null) return ans;
getPath(root, targetSum);
return ans;
}
public void getPath(TreeNode node, int count) {
path.add(node.val); // 路径中加入当前节点
count -= node.val; // 记录当前节点值
if (node.left == null && node.right == null && count == 0) { // 符合条件,更新结果
List<Integer> temp = new ArrayList<>(path);
ans.add(temp);
return;
}
if (node.left == null && node.right == null) return;
if (node.left != null) { // 存在左节点,遍历左节点
getPath(node.left, count);
path.remove(path.size() - 1); // 回溯
}
if (node.right != null) { // 存在右节点,遍历右节点
getPath(node.right, count);
path.remove(path.size() - 1); // 回溯
}
return;
}
}
106.从中序与后序序列构造二叉树
思路:采用递归的方式不断分割数组,然后构造节点。
class Solution {
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 index = 0;
for (;index < inorder.length; index++) {
if (inorder[index] == root.val) {
break;
}
}
int[] leftInorder = new int[index];
int[] leftPostorder = new int[index];
for (int i = 0; i < index; i++) {
leftInorder[i] = inorder[i];
leftPostorder[i] = postorder[i];
}
int[] rightInorder = new int[inorder.length - 1 - index];
int[] rightPostorder = new int[inorder.length - 1 - index];
for (int i = 0; i < rightInorder.length; i++) {
rightInorder[i] = inorder[i + index + 1];
rightPostorder[i] = postorder[i + index];
}
TreeNode left = buildTree(leftInorder, leftPostorder);
TreeNode right = buildTree(rightInorder, rightPostorder);
root.left = left;
root.right = right;
return root;
}
}
随想录中写法,避免了大量的数组操作,注意区间定义一致。
class Solution {
Map<Integer, Integer> map; // 方便根据数值查找位置
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) { // 用map保存中序序列的数值对应位置
map.put(inorder[i], i);
}
return findNode(inorder, 0, inorder.length, postorder,0, postorder.length); // 前闭后开
}
public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {
// 参数里的范围都是前闭后开
if (inBegin >= inEnd || postBegin >= postEnd) { // 不满足左闭右开,说明没有元素,返回空树
return null;
}
int rootIndex = map.get(postorder[postEnd - 1]); // 找到后序遍历的最后一个元素在中序遍历中的位置
TreeNode root = new TreeNode(inorder[rootIndex]); // 构造结点
int lenOfLeft = rootIndex - inBegin; // 保存中序左子树个数,用来确定后序数列的个数
root.left = findNode(inorder, inBegin, rootIndex,
postorder, postBegin, postBegin + lenOfLeft);
root.right = findNode(inorder, rootIndex + 1, inEnd,
postorder, postBegin + lenOfLeft, postEnd - 1);
return root;
}
105.从前序与中序序列构造二叉树
思路:与上一题解法相同。
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); // map中存放中序数组,方便快速查找根节点位置。
}
return getTree(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
public TreeNode getTree(int[] preorder, int pStart, int pEnd, int[] inorder, int inStart, int inEnd) {
if (pStart >= pEnd || inStart >= inEnd) return null; // 没有元素了,返回null
int rootIndex = map.get(preorder[pStart]); // 根节点在中序数组中的下标
TreeNode root = new TreeNode(inorder[rootIndex]);
int leftLen = rootIndex - inStart; // 左孩子数组的长度
root.left = getTree(preorder, pStart + 1, pStart + 1 + leftLen, inorder, inStart, rootIndex);
root.right = getTree(preorder, pStart + 1 + leftLen, pEnd, inorder, rootIndex + 1, inEnd);
return root;
}
}