【91 算法-基础篇】03.树
例题一:104. 二叉树的最大深度
采用两种递归算法。
Solution 1: top-down recursive solution
class Solution {
//top-down recursive solution
int ans = 0;
public int maxDepth(TreeNode root) {
find(root, 1);
return ans;
}
public void find(TreeNode node, int depth){
if(node == null)
return;
if(node.left == null && node.right == null)
ans = Math.max(depth, ans);
find(node.left, depth+1);
find(node.right, depth+1);
}
}
Solution 2: bottom-up recursive solution
class Solution {
//bottom-up recursive solution
public int maxDepth(TreeNode root) {
int ans = find(root);
return ans;
}
public int find(TreeNode node){
if(node == null)
return 0;
int leftAns = find(node.left);
int rightAns = find(node.right);
return Math.max(leftAns, rightAns)+1;
}
}
例题二:100. 相同的树
方法一:递归
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if( p == null && q == null)
return true;
if(p == null || q == null)
return false;
if(p.val != q.val)
return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
方法二:迭代(BFS)
class Solution {
public boolean check(TreeNode p, TreeNode q){
if(p == null && q == null)
return true;
if(p == null || q == null)
return false;
return p.val == q.val;
}
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null)
return true;
if(!check(p, q))
return false;
Queue<TreeNode> pQ = new LinkedList<>();
Queue<TreeNode> qQ = new LinkedList<>();
pQ.add(p);
qQ.add(q);
while(pQ.size() > 0){
p = pQ.remove();
q = qQ.remove();
if(!check(p,q))
return false;
if(p != null){
pQ.add(p.left);
pQ.add(p.right);
qQ.add(q.left);
qQ.add(q.right);
}
}
return true;
}
}
例题三:129. 求根到叶子节点数字之和
方法一:DFS
class Solution {
int res = 0;
public int sumNumbers(TreeNode root) {
if(root == null)
return res;
helper(root, 0);
return res;
}
public void helper(TreeNode node, int sum){
int temp = sum * 10 + node.val;
if(node.left == null && node.right == null)
res += temp;
else{
if(node.left != null)
helper(node.left, temp);
if(node.right != null)
helper(node.right, temp);
}
}
}
方法二:BFS
class Solution {
public int sumNumbers(TreeNode root) {
int res = 0;
if(root == null)
return res;
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
queue.add(new Pair(root, 0));
while(!queue.isEmpty()){
Pair<TreeNode, Integer> pair = queue.remove();
if(pair.getKey().left == null && pair.getKey().right == null)
res += pair.getValue() * 10 + pair.getKey().val;
if(pair.getKey().left != null)
queue.add(new Pair(pair.getKey().left, pair.getValue() * 10 + pair.getKey().val));
if(pair.getKey().right != null)
queue.add(new Pair(pair.getKey().right, pair.getValue() * 10 + pair.getKey().val));
}
return res;
}
}
例题四:513. 找树左下角的值
#37
方法一:BFS
class Solution {
public int findBottomLeftValue(TreeNode root) {
int maxLevel = -1, level = 0, res = 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0; i < size; i++){
TreeNode node = queue.remove();
if(level > maxLevel){
maxLevel = level;
res = node.val;
}
if(node.left != null)
queue.add(node.left);
if(node.right != null)
queue.add(node.right);
}
level++;
}
return res;
}
}
方法二:DFS
class Solution {
int maxLevel = -1, res = 0;
public int findBottomLeftValue(TreeNode root) {
preOrder(root, 0);
return res;
}
public void preOrder(TreeNode node, int level){
if(node == null)
return;
level++;
if(node.left == null && node.right == null && level > maxLevel){
maxLevel = level;
res = node.val;
}
preOrder(node.left, level);
preOrder(node.right, level);
}
}
例题五:105. 从前序与中序遍历序列构造二叉树
#38
前序遍历和中序遍历,后序遍历和中序遍历,都可以生成唯一的一个二叉树,而前序遍历和后续遍历不可以。
前序遍历和中序遍历
前续遍历序列的第一个节点是二叉树的根节点,这个根节点的左子树节点都位于中序遍历序列根节点的左面,这个根节点的右子树节点都位于中序遍历序列根节点的右面,依次类推,通过递归的方式创建一个二叉树。
class Solution {
int preIndex = 0;
int[] preorder, inorder;
HashMap<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
this.inorder = inorder;
for(int i = 0; i < inorder.length; i++){
map.put(inorder[i], i);
}
return helper(0, inorder.length - 1);
}
public TreeNode helper(int left, int right){
if(left > right)
return null;
TreeNode node = new TreeNode();
node.val = preorder[preIndex++];
int inIndex = map.get(node.val);
node.left = helper(left, inIndex-1);
node.right = helper(inIndex+1, right);
return node;
}
}
后序遍历和中序遍历
后续遍历序列的最后一个节点是二叉树的根节点,这个根节点的左子树节点都位于中序遍历序列根节点的左面,这个根节点的右子树节点都位于中序遍历序列根节点的右面,依次类推,通过递归的方式创建一个二叉树。
class Solution {
int postIndex;
Map<Integer, Integer> map;
int[] inorder, postorder;
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.inorder = inorder;
this.postorder = postorder;
map = new HashMap<>();
for(int i = 0; i < inorder.length; i++){
map.put(inorder[i], i);
}
postIndex = postorder.length - 1;
return helper(0, inorder.length-1);
}
public TreeNode helper(int left, int right){
if(left > right)
return null;
TreeNode node = new TreeNode();
node.val = postorder[postIndex];
postIndex--;
int inIndex = map.get(node.val);
node.right = helper(inIndex + 1, right);
node.left = helper(left, inIndex - 1);
return node;
}
}
例题六:124. 二叉树中的最大路径和
思路
从树的叶子节点开始考虑,它的最大路径和max_gain就是它本身的值。它的父节点的max_gain和考虑了它的左子树和右子树的max_gain(其实叶子节点也是),它本身的max_gain就是它的左右子树的max_gain加上父节点的值(如果左右子树的max_gain中有负数,我们就取0,相当于不算它)。我们对树中的每一个节点都求一下它的max_gain,取最大值即可。值得注意的是,每一个节点作为根节点的子树对它的父节点的max_gain是它的值加上左右子树max_gain中较大的那个。
代码
class Solution {
int max_sum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
max_gain(root);
return max_sum;
}
public int max_gain(TreeNode node){
if(node == null)
return 0;
int left_gain = Math.max(0, max_gain(node.left));
int right_gain = Math.max(0, max_gain(node.right));
int connectSum = left_gain + right_gain + node.val;
max_sum = Math.max(max_sum, connectSum);
return node.val + Math.max(left_gain, right_gain);
}
}
复杂度
- 时间复杂度 O ( n ) O(n) O(n),n为节点的数量
- 空间复杂度 O ( n ) O(n) O(n),最坏的情况下,skewed binary tree