代码随想录算法刷题训练营第十三天 | 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和 222.完全二叉树的节点个数

 二叉树结点的深度是指当前结点到根节点的海拔;前序求深度

二叉树结点的高度是当前结点到最远叶子结点的海拔;后序求高度

 110. 平衡二叉树

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:代码随想录算法公开课 | 最强算法公开课 | 代码随想录

 平衡二叉树:所有结点左右子树深度相差不超过1

 思路:因为是所有结点的深度,所以可以推卸责任,也就是可以递归

1. 确定递归返回值和参数,返回值为结点深度,如果以该结点为根的子树不是平衡二叉树就返回-1,作为标记;

2. 终止条件,结点为null返回0;

3. 推卸责任,把任务推给左孩子右孩子,让他们返回-1或深度,根据他们返回的值,如果左孩子和右孩子深度差值大于1,就返回-1,也算一个终止条件

递归法
public int isTrue(TreeNode node) {
    if(node == null) return 0;
    int leftHeight = isTrue(node.left);//推卸责任
    if(leftHeight == -1)return -1;
    int rightHeight = isTrue(node.right);
    if(rightHeight == -1)return -1;
    if(Math.abs(leftHeight - rightHeight) > 1) return -1;
    else return 1 + Math.max(leftHeight,rightHeight);
}

257. 二叉树的所有路径

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解: 代码随想录算法公开课 | 最强算法公开课 | 代码随想录

 明确题目: 返回从根节点到叶子结点的所有路径: ["1->2","1->4->8"]

思路:

1. 递归回溯,一个集合放路径(支持回溯),一个集合放路径结果

  • 参数返回值: 参数为结点和集合路径,返回值为空
  • 终止条件,结点左右结点为空
  • 回溯: 推卸责任给孩子后,再从集合路径中取出该结点
  • 推卸责任: 如果左右孩子不为空,就走他们
public void traversal(TreeNode node,List<String> path) {
    path.add(node.val + "");//中;中写在这里可以让最后一个结点也加进路径中
    if(node.left == null && node.right == null) {
        String paths = path.stream().collect(Collectors.joining("->"));
        result.add(paths);
    }
    if(node.left != null) {
        traversal(node.left, path);//左
        path.remove(path.size()-1);
    }
    if(node.right != null) {
        traversal(node.right, path);//右
        path.remove(path.size()-1);
    }
}

他是从上到下,所以用前序遍历

同理,回溯也就是恢复现场(c++)

void traversal(TreeNode* cur, string path, vector<string>& result) {
    path += to_string(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中
    if (cur->left == NULL && cur->right == NULL) {
        result.push_back(path);
        return;
    }
    if (cur->left) {
        path += "->";
        traversal(cur->left, path, result); // 左
        path.pop_back(); // 回溯 '>'
        path.pop_back(); // 回溯 '-'
    }
    if (cur->right) {
        path += "->";
        traversal(cur->right, path, result); // 右
        path.pop_back(); // 回溯'>'
        path.pop_back(); // 回溯 '-'
    }
}

2. 迭代法,还原递归

public List<String> binaryTreePaths(TreeNode root) {
    // traversal(root,path);
    Deque<String> paths = new LinkedList<>();
    Deque<TreeNode> deque = new LinkedList<>();
    if(root != null)deque.push(root);
    paths.push(String.valueOf(root.val));
    while(!deque.isEmpty()) {
        TreeNode mid = deque.pop();//中结点
        String path = paths.pop();//取出结点对应路径
        if(mid.left == null && mid.right == null) {
            result.add(path);
        }
        if(mid.right != null) {//右
            deque.push(mid.right);
            paths.push(path + "->" + String.valueOf(mid.right.val));
        }
        if(mid.left != null) {//左
            deque.push(mid.left);
            paths.push(path + "->" + String.valueOf(mid.left.val));
        }
    }
    return result;
}

用两个栈,一个遍历,一个存路径;遍历用前序遍历

取出的路径加上孩子,遇到叶子就加到结果里;其实是用栈保存了某层的路径,跟递归是一样的

404.左叶子之和

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:代码随想录算法公开课 | 最强算法公开课 | 代码随想录

 思路:左叶子就是叶子结点,同时也是左结点;

1. 可以用递归实现

  • 参数和返回值: 返回值为左结点之和,参数为结点
  • 终止条件: 如果当前结点的左结点不为空,并且左结点的左右孩子为空,就返回左结点的值加上左右孩子的左叶子之和;否则就返回左右孩子的左叶子之和
  • 推卸责任: 终止条件里面的左右孩子的左叶子之和
public int sumLeftLeaves(TreeNode root) {
    if(root == null) return 0;
    TreeNode left = root.left;
    TreeNode right = root.right;
    int sum = 0;
    //是左叶子
    if(left != null && left.left == null && left.right == null) {
        sum = left.val; 
    }
    return sum + sumLeftLeaves(left) + sumLeftLeaves(right);
}

2. 迭代法:(层序遍历)

对左结点进行判断处理

public int sumOfLeftLeaves(TreeNode root) {
    if(root == null) return 0;
    int sum = 0;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    while(!queue.isEmpty()) {
        int size = queue.size();
        for(int i=0;i<size;i++) {
            TreeNode node = queue.poll();
            if(node.left != null) {
                queue.offer(node.left);
                if(node.left.left == null && node.left.right == null) sum += node.left.val;
            }
            if(node.right != null) queue.offer(node.right);
        }
    }
    return sum;
    // return sumLeftLeaves(root);
}

222.完全二叉树的节点个数

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:代码随想录算法公开课 | 最强算法公开课 | 代码随想录

完全二叉树是满二叉树从下到上,从右到左拿走一些结点 

 思路:

1. 普通: 可以用迭代法,通用求二叉树结点个数;层序遍历,出队一个就把计数加一

层序遍历(迭代法)
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
    int size = queue.size();
    for(int i=0; i<size; i++) {
        TreeNode node = queue.poll();
        result++;
        if(node.left != null) queue.offer(node.left);
        if(node.right != null) queue.offer(node.right);
    }
}

2.  普通:递归法,把责任推给左右孩子,让他们返回结点数,也就是后续遍历,左右中

int getNodesNum(TreeNode* cur) {
    if (cur == NULL) return 0;
    int leftNum = getNodesNum(cur->left);      // 左
    int rightNum = getNodesNum(cur->right);    // 右
    int treeNum = leftNum + rightNum + 1;      // 中
    return treeNum;
}

3. 递归法,利用完全二叉树里面有满二叉树,满二叉树结点的计算是 2<<h-1 ;

递归函数要做的是算满二叉树的结点数

  • 返回值和参数: 返回值为结点数目,参数为结点
  • 终止条件: 结点为null
  • 推卸责任的过程: 就是把本层要做的推给左右孩子那一层;

需要一个判断,如果以当前为根的子树是满二叉树就根据高度计算结点数返回,如果不是,就推卸责任给孩子结点

需要孩子结点把他的结点数从下到上返回给父亲,所以用后序遍历,左右中

public int countNodess(TreeNode node) {
    if(node == null) return 0;
    int leftNode = 0,rightNode = 0;
    TreeNode left = node.left;
    TreeNode right = node.right;
    while(left != null) {
        left = left.left;
        leftNode++;
    }
    while(right != null) {
        right = right.right;
        rightNode++;
    }
    if(leftNode == rightNode) return (2 << leftNode)-1;

    int leftTreeNum = countNodess(node.left);//左
    int rightTreeNum = countNodess(node.right);//右
    return leftTreeNum + rightTreeNum + 1;//中
}

其中判断是否为满二叉树用到完全二叉树的性质,只要最左孩子的深度等于最右孩子的深度,那他就是满二叉树,否则就是两个孩子的结点数+1;

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值