LeetCode刷题:树1

四种基本遍历

前中后序遍历都是属于dfs
层序属于bfs

本文主要涉及类型:后序遍历的状态转移,有返回值的dfs,通过左右孩子推出中间节点的值或者状态然后继续上推
前序后序层序遍历见树2

前序

 public void preTraversal(Node node){
       if (node == null) //很重要,必须加上 当遇到叶子节点用来停止向下遍历
             return;
         System.out.print(node.getValue()+" ");
        preTraversal(node.getLeft());
        preTraversal(node.getRight());
 }

中序

public void MidTraversal(Node node){
      if (node == null)
          return;
     MidTraversa(node.getLeft());
     System.out.print(node.getValue()+" ");
     MidTraversa(node.getRight());
 }

后序

 public void postTraversal(Node node){
         if (node == null)
                 return;
        postTraversal(node.getLeft());
        postTraversal(node.getRight());
        System.out.print(node.getValue()+" ");
 }

stack写法

三种顺序的stack写法

前序:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左
                // 中,push NULL是一个标志位,当前中中间节点
                st.push(node);                          
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};

后序:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // 中
                st.push(NULL);

                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左

            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};

中序:

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
                if (node->right) st.push(node->right);  // 添加右节点(空节点不入栈)

                st.push(node);                          // 添加中节点
                st.push(NULL); // 中节点访问过,但是还没有处理,加入空节点做为标记。

                if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈)
            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
                st.pop();           // 将空节点弹出
                node = st.top();    // 重新取出栈中元素
                st.pop();
                result.push_back(node->val); // 加入到结果集
            }
        }
        return result;
    }
};

层序遍历

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<>();
        BFS(root, res);
        return res;
    }
 
    private void BFS(TreeNode treeNode, List<List<Integer>> res) {
        if (treeNode == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(treeNode);
        while (!queue.isEmpty()) {
            List<Integer> level = new LinkedList<>();
            int n = queue.size();
            for(int i = 0; i < n; i++) {
                TreeNode tmp = queue.poll();
                if(tmp != null) {
                    level.add(tmp.val);
                    queue.offer(tmp.left);
                    queue.offer(tmp.right);
                }
            }
            if(level.size() > 0) {
                res.add(level);
            }
        }
    }

后续遍历:dfs是为了状态转移 + 结果判定或者递归处理

自底向上的解法,配合状态转移与最终结果记录,一般采用后续遍历

判断是否是平衡二叉树

https://leetcode-cn.com/problems/balanced-binary-tree/
在这里插入图片描述

核心思路:
自底向上,有状态的转移;
后序遍历,左孩子错右孩子错那么parent一定是错的。
返回值与存储结构

class Solution {
    public boolean isBalanced(TreeNode root) {
        return height(root) >= 0;
    }
 
    public int height(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = height(root.left);
        int rightHeight = height(root.right);
        if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
            return -1; // -1 作为失败标志
        } else {
            return Math.max(leftHeight, rightHeight) + 1;  // 正常的高度返回
        }
    }
}
class Solution {
    // 最终结果
    boolean res = true;
    public boolean isBalanced(TreeNode root) {
        dfs(root);
        return res;
    }

    private int dfs(TreeNode root) {
        if(root == null || !res) {
            // !res 提前剪枝,没必要算到最后
            return 0;
        }
        int leftLength = dfs(root.left);
        int rightLength = dfs(root.right);
        if(Math.abs(leftLength - rightLength) > 1) {
            res = false;
        }
        return Math.max(leftLength, rightLength) + 1;
    }
}

判断二叉树的边长:左右孩子最大高度之和

同类题1:求左右孩子最大高度之和
https://leetcode-cn.com/problems/diameter-of-binary-tree/ 在这里插入图片描述后序遍历的又一个例子,变来变去的只是从子问题到大问题的推导

class Solution {
    Integer ans = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        if(root == null) {
            return 0;
        }
        postOrder(root);
        return ans - 1;
    }
 
    private int postOrder(TreeNode root) {
        if(root == null) {
            return 0;
        }
        int left = postOrder(root.left);
        int right = postOrder(root.right);
        ans = Math.max(ans,left + right + 1); // 最终结果:使用一个公共字段保存结果
        return Math.max(left, right) + 1; // 当前状态:大问题的解存储的状态转移不同,存储的实际上是高度
    }
}

判断二叉树路径和:左右节点最大和

同类题2 :求左右节点最大和
在这里插入图片描述
在这里插入图片描述

class Solution {
    Integer ans =  Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        if(root == null) {
            return 0;
        }
        postOrder(root);
        return ans;
    }
 
    private int postOrder(TreeNode root) {
        if(root == null) {
            return 0;
        }
        // 如果最终结果小于0,不如不选
        int left = Math.max(postOrder(root.left), 0);
        int right = Math.max(postOrder(root.right), 0);
        // 状态转移:最终的结果是,某个子树root + 左右孩子值
        ans = Math.max(ans, left + right + root.val); 
        // 状态转移:每一步dfs返回的语义是,必选root一个子树情况下最大的结果
        // 因为必选root,因此不能同时遍历左右孩子,只能选择一支或者不选择
        return Math.max(left, right) + root.val;
    }
}

翻转二叉树

在这里插入图片描述

在这里插入图片描述

简单的后续遍历:

public TreeNode invertTree(TreeNode root) {
        if(root == null) {
            return root;
        }
        return postOrder(root);
    }
 
    private TreeNode postOrder(TreeNode root) {
        if(root == null) {
            return root;
        }
        // 无需汇总结果,只需要递归处理所有子树,然后处理自己
        postOrder(root.left);
        postOrder(root.right);
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        return root;
    }

求最大BST树

在这里插入图片描述
在这里插入图片描述

二叉搜索树特征:中序遍历val递增
还是后序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
 
    class Result {
        TreeNode node; // BST根节点
        int size; // BST的size
        int max; // BST的最大值
        int min; // BST的最小值
    }
 
    public int largestBSTSubtree(TreeNode root) {
        Result r = visit(root);
        return r == null ? 0 : r.size;
    }
 
    public Result visit(TreeNode node) {
        if (node == null) return null;
 
        Result l = null, r = null;
        if (node.left != null) l = visit(node.left);
        if (node.right != null) r = visit(node.right);
 
        // 当前树为BST
        boolean lValid = (l == null || (l.node == node.left && l.max < node.val));
        boolean rValid = (r == null || (r.node == node.right && r.min > node.val));
        if (lValid && rValid) {
            Result result = new Result();
            result.node = node;
            result.max = r == null ? node.val : r.max;
            result.min = l == null ? node.val : l.min;
            result.size = (l == null ? 0 : l.size) + (r == null ? 0 : r.size) + 1;
            return result;
        }
 
        // 左右子树中找到了BST
        if (l != null && r != null) {
            return l.size > r.size ? l : r;
        }
        if (l != null) return l;
        if (r != null) return r;
 
        return null;
    }
}
 
作者:jzj1993
链接:https://leetcode-cn.com/problems/largest-bst-subtree/solution/si-lu-qing-xi-de-javadai-ma-onfu-za-du-1ms-by-jzj1/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

最近公共祖先

https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/在这里插入图片描述还是后序遍历,父节点的状态转移方程(返回值)如上
最后结果可以通过放置在外面代入求得

class Solution {
 
    private TreeNode ans;
 
    public Solution() {
        this.ans = null;
    }
 
    private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return false;
        boolean lson = dfs(root.left, p, q);
        boolean rson = dfs(root.right, p, q);
      // 结果存储
        if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))) {
            ans = root;
        } 
      // 状态转移
        return lson || rson || (root.val == p.val || root.val == q.val);
    }
 
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.dfs(root, p, q);
        return this.ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值