代码随想录训练营第十四天 | 226.翻转二叉树 (优先掌握递归)101. 对称二叉树 (优先掌握递归) 104.二叉树的最大深度 (优先掌握递归)111.二叉树的最小深度 (优先掌握递归)

226.翻转二叉树(需要考虑遍历方式)

所谓的遍历的前中后序:指的是“交换”这个行为。是先交换根节点的左右孩子?还是先交换左孩子的左右孩子?还是先交换右孩子的左右孩子?

深度递归的前中后序

前后序可以,但中序不行:因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)

前序:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        return invert1(root);
    }

    // 递归
    private TreeNode invert1(TreeNode node){
        if(node==null) return node;
        TreeNode temp = node.left;
        node.left = invert1(node.right);
        node.right = invert1(temp);
        return node;
    }
}

伪中序遍历:看似是中序,实际上不是。

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        invertTree(root->left);         // 左
        swap(root->left, root->right);  // 中
        invertTree(root->left);         // 注意 这里依然要遍历左孩子,因为中间节点已经翻转了
        return root;
    }
};

深度迭代的前中后序

迭代法的中序遍历可以:这是用栈来遍历,而不是靠指针来遍历,避免了递归法中翻转了两次的情况

广度迭代

101. 对称二叉树 (难想)

递归

错误写法:不是每个节点的左右孩子的值相同,而是整体是对称的。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return is(root);
    }

    // 递归
    private boolean is(TreeNode root){
        if(root.left == null && root.left==null) return true;
        else if(root.left!=null && root.right!=null) return is(root.right) && is(root.left);
        else return false;
    }
}

比较的是两棵子树:同时遍历左子树、右子树,两者是否一致。
内侧节点、外侧节点:我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。
此时的后序遍历:准确的来说是一个树的遍历顺序是左右中,另一个树的遍历顺序是右左中

为什么想到后序遍历:先遍历最完底层的元素,然后就返回到上一层进行遍历。

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return compare(root.left, root.right);
    }

    // 递归
    private boolean compare(TreeNode left, TreeNode right){
        if(left==null && right==null) return true;
        else if(left!=null && right!=null){
            if(left.val==right.val){
            	// 按照访问顺序来说,感觉像是前序???
            	// 外部:左孩子的左孩子 == 右孩子的右孩子
            	// 内部:左孩子的右孩子 == 右孩子的左孩子
                return compare(left.left, right.right) && compare(left.right, right.left);
            }else{
                return false;
            }
        } else return false;
    }
}

迭代

104.二叉树的最大深度 (优先掌握递归)

递归

class Solution {
    public int maxDepth(TreeNode root) { // 深度从1开始
        return getDepth(root, 1);
    }

    private int getDepth(TreeNode node, int depth){ // depth是node的深度
        if(node==null) return depth-1;
        if(node.left==null && node.right==null) return depth;
        else return Math.max(getDepth(node.left, depth+1), getDepth(node.right, depth+1));
    }
}

迭代

111.二叉树的最小深度 (优先掌握递归)

递归

错误解法:左右节点都为空才是叶子节点,而只有一个子节点为空不是叶子节点。

class Solution {
    public int minDepth(TreeNode root) {
        return getMinDepth(root, 1);
    }

    private int getMinDepth(TreeNode node, int depth){
        // 终止:如果是null(叶子节点的子节点)
        if(node==null) return depth-1;
        // 递归:如果是非叶子节点
        return Math.min(getMinDepth(node.left, depth+1), getMinDepth(node.right, depth+1));
    }
}

修改:

class Solution {
    public int minDepth(TreeNode root) {
        if(root==null) return 0;
        return getMinDepth(root, 1);
    }

    private int getMinDepth(TreeNode node, int depth){
        // 终止:如果是空节点(父节点有只有一个节点
        if(node==null) return Integer.MAX_VALUE;

        // 终止:如果叶子节点
        if(node.left==null && node.right==null) return depth;
        
        // 递归:如果是非叶子节点
        return Math.min(getMinDepth(node.left, depth+1), getMinDepth(node.right, depth+1));
    }
}

随想录解法:原版与精简版
重点:原版能看出来是后序遍历,而精简版看不出来。

// 原版
class Solution {
public:
    int getDepth(TreeNode* node) {
        if (node == NULL) return 0;
        int leftDepth = getDepth(node->left);           // 左
        int rightDepth = getDepth(node->right);         // 右
                                                        // 中
        // 当一个左子树为空,右不为空,这时并不是最低点
        if (node->left == NULL && node->right != NULL) { 
            return 1 + rightDepth;
        }   
        // 当一个右子树为空,左不为空,这时并不是最低点
        if (node->left != NULL && node->right == NULL) { 
            return 1 + leftDepth;
        }
        int result = 1 + min(leftDepth, rightDepth);
        return result;
    }

    int minDepth(TreeNode* root) {
        return getDepth(root);
    }
};

// 精简版
class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->left == NULL && root->right != NULL) {
            return 1 + minDepth(root->right);
        }
        if (root->left != NULL && root->right == NULL) {
            return 1 + minDepth(root->left);
        }
        return 1 + min(minDepth(root->left), minDepth(root->right));
    }
};

 // 前序
class Solution {
private:
    int result;
    void getdepth(TreeNode* node, int depth) {
        // 函数递归终止条件
        if (node == nullptr) {
            return;
        }
        // 中,处理逻辑:判断是不是叶子结点
        if (node -> left == nullptr && node->right == nullptr) {
            result = min(result, depth);
        }
        if (node->left) { // 左
            getdepth(node->left, depth + 1);
        }
        if (node->right) { // 右
            getdepth(node->right, depth + 1);
        }
        return ;
    }

public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) {
            return 0;
        }
        result = INT_MAX;
        getdepth(root, 1);
        return result;
    }
};

迭代

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值