数据结构——leetcode(树练习1)【java】

递归

leetcode-104-二叉树的最大深度

力扣-104
题目:给定一个二叉树,找出其最大深度。
示例
给定二叉树 [3,9,20,null,null,15,7],返回它的最大深度 3 。

   3
   / \
  9  20
    /  \
   15   7

思路:遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right))+1;

    }
}

时间复杂度:每个结点只访问一次,因此时间复杂度为 O(N),其中 N 是结点的数量。
空间复杂度:在最糟糕的情况下,树是完全不平衡的,例如每个结点只剩下左子结点,递归将会被调用 N 次(树的高度),因此保持调用栈的存储将是 O(N)。但在最好的情况下(树是完全平衡的),树的高度将是log(N)。因此,在这种情况下的空间复杂度将是 O(log(N))。

leetcode-110-平衡二叉树

力扣-110
题目:给定一个二叉树,判断它是否是高度平衡的二叉树。一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例
给定二叉树 [3,9,20,null,null,15,7
返回true

   3
   / \
  9  20
    /  \
   15   7

思路:遍历,参考平衡二叉树(从底至顶,从顶至底).

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //自底向上
class Solution {
    public boolean isBalanced(TreeNode root) {
        return MaxDepth(root)!=-1;
   
    }
    public int MaxDepth(TreeNode root){
        if(root == null) return 0;
        int left = MaxDepth(root.left);
         if(left == -1) return -1;
        int right = MaxDepth(root.right);
         if(right == -1) return -1; 
        return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
    } 
}

时间复杂度:O(N),N 为树的节点数;最差情况下,需要递归遍历树的所有节点。
空间复杂度 :O(N) 最差情况下(树退化为链表时),系统递归需要使用 O(N)的栈空间。

leetcode-543-二叉树的直径

力扣-543
题目:给定一个二叉树,找出直径。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例

给定二叉树

      1
     / \
    2   3
   / \     
  4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

思路:遍历,以每一个节点为中心点计算最长路径(左子树边长+右子树边长)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        if(root == null){
            return 0;
        }
        dfs(root);
        return max;

    }
    public int dfs(TreeNode root){
        if(root.left == null&& root.right ==null){
            return 0;
        }
        int leftSize = root.left == null? 0:dfs(root.left)+1;
        int rightSize = root.right == null? 0:dfs(root.right)+1;
        max = Math.max(max,leftSize+rightSize);
        return Math.max(leftSize,rightSize);
    }
}

时间复杂度:O(N),其中N 为二叉树的节点数,即遍历一棵二叉树的时间复杂度,每个结点只被访问一次。

空间复杂度:O(Height),其中 Height 为二叉树的高度。由于递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,而递归的深度显然为二叉树的高度,并且每次递归调用的函数里又只用了常数个变量,所以所需空间复杂度为 O(Height)。

类似解法的树算法题:
124. 二叉树中的最大路径和
687. 最长同值路径

leetcode-226-翻转二叉树

力扣-226
题目:翻转一棵二叉树。
示例
输入:

   	   4
  	 /   \
  	2     7
   / \   / \
  1   3 6   9

输出:

        4
       /  \
     7     2
    / \   / \
   9   6 3   1

思路:遍历,前序、中序、后序遍历

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null){
            return null;
        }
        //前序遍历
        TreeNode rightTree = root.right;
        root.right = invertTree(root.left);
        root.left = invertTree(rightTree);
        return root;
    }
}

时间复杂度: 树中的每个节点都只被访问一次,那么时间复杂度就是 O(n)

空间复杂度: 使用了递归,在最坏情况下栈内需要存放 O(h)其中 h 是树的高度,空间复杂度为 O(n)。

leetcode-617-合并二叉树

力扣-617
题目:合并二叉树。
示例

输入:

Tree 1                     Tree 2                  
      1                         2                             
     / \                       / \                            
    3   2                     1   3                        
   /                           \   \                      
  5                             4   7                  

输出:
合并后的树:

     3
    / \
   4   5
  / \   \ 
 5   4   7

思路:遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if(t1 == null){
            return t2;
        }
        if(t2 == null){
            return t1;
        }
        t1.val+=t2.val;
        t1.left = mergeTrees(t1.left,t2.left);
        t1.right = mergeTrees(t1.right,t2.right);
        return t1;
    }
}

时间复杂度: O(N),其中 N是两棵树中节点个数的较小值。

空间复杂度: O(N),在最坏情况下,会递归 N层,需要 O(N) 的栈空间。

leetcode-112-路径总和

力扣-112
题目:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
示例
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \      \
    7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

思路:递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null){
            return false;
        }
        if(root.left==null&&root.right==null){
            return sum==root.val;
        }
        return hasPathSum(root.left,sum-root.val)||hasPathSum(root.right,sum-root.val);
    }
}

时间复杂度: O(N),其中 N 是树的节点数。对每个节点访问一次。

空间复杂度: O(H),其中 H 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(N)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logN)。

leetcode-437-统计路径和等于一个数的路径数量

力扣-437
题目
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
示例

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1
返回 3。和等于 8 的路径有:
1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11

返回 3。和等于 8 的路径有:

  1. 5 -> 3
  2. 5 -> 2 -> 1
  3. -3 -> 11

思路:双重递归,外面的递归转换root point,里面的递归是在root point下找到路径的方法。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int count;
    public int pathSum(TreeNode root, int sum) {
        if(root == null){
            return 0;
        }
        dfs(root, sum);
        pathSum(root.left,sum);
        pathSum(root.right,sum);
        return count;

    }
    public void dfs(TreeNode root, int sum){
        if(root == null){
            return ;
        }
        sum-=root.val;
        if(sum==0) count+=1;
        dfs(root.left,sum);
        dfs(root.right,sum);

    }
}

leetcode-572-子树

力扣-572
题目:给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。
示例
示例 1:
给定的树 s:

     3
    / \
  4   5
 / \
1   2

给定的树 t:

  4 
 / \
1   2

返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。

示例 2:
给定的树 s:

       3
	  / \
     4   5
    / \
   1   2
  /
 0

给定的树 t:

  4
 / \
1   2

返回 false。

思路:递归,一个树要是另一个树的子树,要么两个数相同,要么是那个树的右子树,或者左子树。空树是任何树的子树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        if(s==null) return false;
        if(t==null) return true;
        return isSameTree(s,t)||isSubtree(s.left,t)||isSubtree(s.right,t);

        
    }
    public boolean isSameTree(TreeNode s,TreeNode t){
        if(s == null&&t == null){
            return true;
        }
        if(s == null||t == null){
            return false;
        }
        if(s.val!=t.val){
            return false;
        }
        return isSameTree(s.left,t.left)&&isSameTree(s.right,t.right);
    }
}

leetcode-101-对称二叉树

力扣-101
题目:给定一个二叉树,检查它是否是镜像对称的。
示例
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

	1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

   1
  / \
 2   2
  \   \
  3    3

思路:递归 || 迭代

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 //递归
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null) return true;
        return isSame(root.left,root.right);
    }
    public boolean isSame(TreeNode root1, TreeNode root2 ){
       if(root1==null &&root2==null){
           return true;
       }
       if(root1 ==null || root2==null||root1.val!=root2.val){
           return false;
       }
       return isSame(root1.left,root2.right)&&isSame(root1.right,root2.left);
    }
}

时间复杂度: 这里遍历了这棵树,渐进时间复杂度为 O(n)。
空间复杂度: 这里的空间复杂度和递归使用的栈空间有关,这里递归层数不超过 n,故渐进空间复杂度为 O(n)。

leetcode-111-二叉树的最小深度

力扣-111
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
示例
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
 /  \
15   7

返回它的最小深度 2.

思路:递归 ,注意当左右子树有一个为空时,最小深度为非空左右子树的深度+1,其他的和求最大深度相反即可

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        //null结点不参与比较
        if(root.left ==null&&root.right!=null){
            return 1+minDepth(root.right);
        }
        if(root.right==null&&root.left!=null){
            return 1+minDepth(root.left);
        }
        return Math.min(minDepth(root.left),minDepth(root.right))+1;

    }
}

时间复杂度:O(N),其中 N 是结点的数量。
空间复杂度:在最糟糕的情况下,树是完全不平衡的,例如每个结点只剩下左子结点,递归将会被调用 N 次(树的高度),因此保持调用栈的存储将是 O(N)。但在最好的情况下(树是完全平衡的),树的高度将是log(N)。因此,在这种情况下的空间复杂度将是 O(log(N))。

leetcode-404-左叶子之和

力扣-404
题目:计算给定二叉树的所有左叶子之和。
示例

    3
   / \
  9  20
 /  \
15   7

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

思路:递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int sum;
    public int sumOfLeftLeaves(TreeNode root) {
        if(root==null) return 0;
        //判断是否是左子叶
        if(root.left!=null&&(root.left.left==null&&root.left.right==null)){
            sum +=root.left.val;
        }
        
        sumOfLeftLeaves(root.left);
        sumOfLeftLeaves(root.right);
         return sum; 

    }
}

时间复杂度:O(N),其中 N 是结点的数量。
空间复杂度:在最糟糕的情况下,树是完全不平衡的,例如每个结点只剩下左子结点,递归将会被调用 N 次(树的高度),因此保持调用栈的存储将是 O(N)。但在最好的情况下(树是完全平衡的),树的高度将是log(N)。因此,在这种情况下的空间复杂度将是 O(log(N))。

leetcode-687-最长同值路径

力扣-687
题目:给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。
示例

输入:

          5
         / \
        4   5
       / \   \
      1   1   5

输出: 2

思路:递归 ,判断左右子树和根节点的值是否相同。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int max = 0;
    public int longestUnivaluePath(TreeNode root) {
        if(root == null){
            return 0;
        }
        dfs(root);
        return max;
    }
    public int dfs(TreeNode root){
        if(root.left==null&&root.right==null){
            return 0;
        }
        int leftsize = root.left==null?0:dfs(root.left)+1;
        int rightsize = root.right==null?0:dfs(root.right)+1;

        if(leftsize>0&&root.left.val!=root.val){
            leftsize = 0;
        }
        if(rightsize>0&&root.right.val!=root.val){
            rightsize = 0;
        }
        max = Math.max(max,leftsize+rightsize);
        return Math.max(leftsize,rightsize);
    }
}

时间复杂度:O(N),其中N 为二叉树的节点数,即遍历一棵二叉树的时间复杂度,每个结点只被访问一次。

空间复杂度:O(Height),其中 Height 为二叉树的高度。由于递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,而递归的深度显然为二叉树的高度,并且每次递归调用的函数里又只用了常数个变量,所以所需空间复杂度为 O(Height)。

leetcode-337-间隔遍历

力扣-337
题目:间隔遍历,取得最大值
示例

  3
 / \
2   3
\   \
 3   1

输出: 7
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

思路:递归
能盗取的最高金额为: 抢劫该节点+抢劫该节点的左孩子的左右子树+抢劫该节点的右孩子的左右子树抢劫该节点的左子树+抢劫该节点的右子树的和 的最大值

class Solution {
    public int rob(TreeNode root) {
        if(root==null) return 0;
        int sum=0;
        if(root.left!=null) sum+=rob(root.left.left)+rob(root.left.right);
        if(root.right!=null)sum+=rob(root.right.left)+rob(root.right.right);
        return Math.max(rob(root.left)+rob(root.right),sum+root.val);
    }
}

leetcode-671-二叉树中第二小结点

力扣-337
题目:给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

示例

输入: 
	2
   / \
  2   5
 / \
5   7

输出: 5
说明: 最小的值是 2 ,第二小的值是 5 。
思路:递归,相当于转换成求,左右子节点中的最小值

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int findSecondMinimumValue(TreeNode root) {
        return traversal(root,root.val);
       
    }
    public int traversal(TreeNode root ,int value){
        if(root == null) return -1;
        if(root.val>value) return root.val;
        //寻找左右子节点,第一个大于自己的
        int leftsum = traversal(root.left,value);
        int rightsum = traversal(root.right,value);
        //如果两棵子树均存在大于最小值的节点,那么返回较小的那一个
        if(leftsum>=0&&rightsum>=0){
            return Math.min(leftsum,rightsum);
        }
        //否则,其余情况均返回较大的那一个
        else{return Math.max(leftsum,rightsum);}
    }
}

层次遍历

leetcode-637-二叉树的层平均值

力扣-337
题目:给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
示例
输入:

 	 3
	/ \
   9  20
 /  \
15   7

输出:[3, 14.5, 11]
解释:
第 0 层的平均值是 3 , 第1层是 14.5 , 第2层是 11 。因此返回 [3, 14.5, 11] 。

思路:层次遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int findSecondMinimumValue(TreeNode root) {
        return traversal(root,root.val);
       
    }
    public int traversal(TreeNode root ,int value){
        if(root == null) return -1;
        if(root.val>value) return root.val;
        //寻找左右子节点,第一个大于自己的
        int leftsum = traversal(root.left,value);
        int rightsum = traversal(root.right,value);
        //如果两棵子树均存在大于最小值的节点,那么返回较小的那一个
        if(leftsum>=0&&rightsum>=0){
            return Math.min(leftsum,rightsum);
        }
        //否则,其余情况均返回较大的那一个
        else{return Math.max(leftsum,rightsum);}
    }
}

leetcode-513-找树左下角的值

力扣-513
题目:给定一个二叉树,在树的最后一行找到最左边的值。
示例
输入:

   2
  / \
 1   3

输出:
1
思路:DFS BFS
1.数据结构上的运用

DFS用递归的形式,用到了栈结构,先进后出。
BFS选取状态用队列的形式,先进先出。

2.复杂度

DFS的复杂度与BFS的复杂度大体一致,不同之处在于遍历的方式与对于问题的解决出发点不同,DFS适合目标明确,而BFS适合大范围的寻找。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int findBottomLeftValue(TreeNode root) {
        //BFS 广度优先搜索
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            root = queue.poll();
            if(root.right!=null) queue.offer(root.right);
            if(root.left!=null) queue.offer(root.left);
        }
        return root.val;
    }
}

class Solution {
    int res;
    int max = Integer.MIN_VALUE;
    public int findBottomLeftValue(TreeNode root) {   //dfs 深度优先搜索
        dfs(root,0);
        return res;    
    }
    public void dfs(TreeNode node,int depth){
        if(node != null){
            if(node.left==null&&node.right==null){
                if(max<depth){
                    max=depth;
                    res = node.val;
                }
            }
            dfs(node.left,depth+1);
            dfs(node.right,depth+1);
        }
    }   
        
}


前中后遍历

leetcode-144-非递归实现二叉树前序遍历

力扣-144
史上最全遍历二叉树详解
题目:给定一个二叉树,返回它的 前序 遍历。(迭代、非递归遍历)

思路:利用栈,根—左—右,栈 根—右—左

   public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            if(node==null) continue;
            ret.add(node.val);
            if(node.right!=null){
                stack.push(node.right);
            }
            if(node.left!=null){
                stack.push(node.left);
            }

        }
        return ret;
    }

leetcode-145-非递归实现二叉树后序遍历

力扣-145
史上最全遍历二叉树详解
题目:给定一个二叉树,返回它的 后序 遍历。(迭代、非递归遍历)

思路:利用栈,根—右—左,然后反转 左—右—根

   public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            if(node==null) continue;
            ret.add(node.val);
            if(node.left!=null){
                stack.push(node.left);
            } 
            if(node.right!=null){
                stack.push(node.right);
            }
        }
        Collections.reverse(ret);
        return ret;
    }
    }

leetcode-94-非递归实现二叉树中序遍历

力扣-94
题目:给定一个二叉树,返回它的 中序 遍历。(迭代、非递归遍历)

思路:利用栈

 public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur!=null||!stack.isEmpty()){
            while (cur != null) {
            stack.push(cur);
            cur = cur.left;
            }
            TreeNode node = stack.pop();
            ret.add(node.val);
            cur = node.right;
        } 
        return ret;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值