Leetcode面T4(1-9)树

Q4.1 节点间通路

节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。

示例1:

输入:n = 3, graph = [[0, 1], [0, 2], [1, 2], [1, 2]], start = 0, target = 2
输出:true
示例2:

输入:n = 5, graph = [[0, 1], [0, 2], [0, 4], [0, 4], [0, 1], [1, 3], [1, 4], [1, 3], [2, 3], [3, 4]], start = 0, target = 4
输出 true
提示:

节点数量n在[0, 1e5]范围内。
节点编号大于等于 0 小于 n。
图中可能存在自环和平行边。

class Solution {
    public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
        map = new HashMap<>();
        visited = new int[n];
        for(int[] edge:graph){
            List<Integer> list = map.getOrDefault(edge[0], new ArrayList<>());
            list.add(edge[1]);
            map.put(edge[0], list);
        }
        return dfs(start, target);
    }
    private boolean dfs(int start, int target){
        if(start == target)
            return true;
        visited[start] = 1;
        if(map.get(start) == null)
            return false;
        List<Integer> list = map.get(start);
        for(int i:list){
            if(visited[i] == 0){
                if(dfs(i, target))
                    return true;
            }
        }
        visited[start] = 1;
        return false;
    }

    private HashMap<Integer, List<Integer>> map;
    private int[] visited;
}

Q4.2 最小高度树

给定一个有序整数数组,元素各不相同且按升序排列,编写一个算法,创建一棵高度最小的二叉搜索树。

示例:
给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

          0 
         / \ 
       -3   9 
       /   / 
     -10  5 

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        TreeNode root;
        root=f(nums,0,nums.length-1);
        return root;
    }
    public TreeNode f(int[] nums,int x,int y){
       if(x>y) return null;
          
            TreeNode root=new TreeNode();
            int s=(x+y)/2;
            root.val=nums[s];
            root.left=f(nums,x,s-1);
            root.right=f(nums,s+1,y);
 
            return root;
    }
}

Q4.3 特定深度节点链表

给定一棵二叉树,设计一个算法,创建含有某一深度上所有节点的链表(比如,若一棵树的深度为 D,则会创建出 D 个链表)。返回一个包含所有深度的链表的数组。

 

示例:

输入:[1,2,3,4,5,null,7,8]

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

输出:[[1],[2,3],[4,5,7],[8]]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode[] listOfDepth(TreeNode root) {
        if (root == null) {
            return null;
        }
        //BFS中的队列
        Queue<TreeNode> queue = new LinkedList<>();
        //先把根节点入队,然后执行“弹一个,加n个”
        queue.add(root);
        //存放每个链表第一个有实际值(非哑元)节点的容器,ArrayList实际上是一个可变长的数组
        List<ListNode> list = new ArrayList<>();
        //只要队列中还有元素就要不停的出队,直到队列中的所有元素都已出队
        while (!queue.isEmpty()) {
            //当前队列的长度,即当前层元素的总个数
            int size = queue.size();
            //链表的头结点,不放实际的值(哑元)
            ListNode head = new ListNode(0);
            //链表移动指针,让它始终指向当表链表的最后一个元素
            ListNode p = head;
            //将当前层的节点逐个出队,把出队节点的子节点入队
            for (int i = 0; i < size; i++) {
                TreeNode poll = queue.poll();
                //链表元素追加
                p.next = new ListNode(poll.val);
                //指针向后移动一个元素,使p指向链表末尾
                p = p.next;
                if (poll.left != null) {
                    //当前出队的节点有左孩子,则左孩子入队
                    queue.add(poll.left);
                }
                if (poll.right != null) {
                    //当前出队的节点有右孩子,则右孩子入队
                    queue.add(poll.right);
                }
            }
            //for循环走完后就遍历完了一层,将存储该层节点的链表第一个有实际值的节点入队
            list.add(head.next);
        }
        //将可变长的数组转化成定长数组(因为函数的返回值要求了返回一个定长数组ListNode[])
        return list.toArray(new ListNode[list.size()]);
    }
}

Q4.4  检查平衡性

实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。


示例 1:
给定二叉树 [3,9,20,null,null,15,7]
    3
   / \
  9  20
    /  \
   15   7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
      1
     / \
    2   2
   / \
  3   3
 / \
4   4
返回 false 。

/**
 * 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) {
        if(root==null) return true;
        int x=depth(root.left);
        int y=depth(root.right);
        if(x-y>=-1&&x-y<=1){
          boolean m=isBalanced(root.left);
          boolean n=isBalanced(root.right);
          return m&&n;
        }else{
            return false;
        }
 
    }
    public int depth(TreeNode root){
        if(root==null) return 0;
        return Math.max(depth(root.left),depth(root.right))+1;
    }
}

Q4.5  合法二叉搜索树

实现一个函数,检查一棵二叉树是否为二叉搜索树。

示例 1:
输入:
    2
   / \
  1   3
输出: true
示例 2:
输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。

二叉搜索树的定义如下

  • 一个节点的左子树上节点的值都小于自身的节点值
  • 一个节点的右子树上节点的值都小于自身的节点值
  • 所有节点的左右子树都必须是二叉搜索树

 采用递归中序遍历方法依次比较当前节点值和后一个节点值的大小,若当前节点值大于等于后一个节点值,则不是 二叉搜索树:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    Integer pre = null;
    
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        if (isValidBST(root.left)) {
            if (pre == null) pre = root.val;
            else {
                if (root.val <= pre) return false;
                else pre = root.val;
            }
            return isValidBST(root.right);
        }
        return false;
        
    }
}

Q4.8  首个共同祖先

设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

    3
   / \
  5   1
 / \ / \
6  2 0  8
  / \
 7   4
示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null)
            return null;
        if(p == root || q == root)
            return root;
        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);
        if(l != null && r != null)
            return root;
        return l == null ? r : l;
    }
}

Q4.9  二叉搜索树序列

从左向右遍历一个数组,通过不断将其中的元素插入树中可以逐步地生成一棵二叉搜索树。给定一个由不同节点组成的二叉搜索树,输出所有可能生成此树的数组。

 

示例:
给定如下二叉树

        2
       / \
      1   3
返回:

[
   [2,1,3],
   [2,3,1]
]

分析:

根据题意分析可知,插入元素的顺序必须从根节点开始插入,也就是先插入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 {
    public List<List<Integer>> BSTSequences(TreeNode root) {
        res = new LinkedList<>();
        if(root == null){
            res.add(new LinkedList<>());
            return res;
        }
        LinkedList<TreeNode> list = new LinkedList<>();
        LinkedList<Integer> path = new LinkedList<>();
        path.add(root.val);
        getSequences(root, list, path);
        return res;
    }
    private void getSequences(TreeNode root, LinkedList<TreeNode> list, LinkedList<Integer> path){
        if(root == null){
            return;
        }
        if(root.left != null)
            list.add(root.left);
        if(root.right != null)
            list.add(root.right);
        if(list.isEmpty()){
            res.add(new LinkedList<>(path));
            return;
        }
        int len = list.size();
        for(int i = 0; i < len; ++i){
            TreeNode cur = list.get(i);
            list.remove(i);
            path.add(cur.val);
            getSequences(cur, new LinkedList<>(list), path);
            path.removeLast();
            list.add(i, cur);
        }
    }
    private List<List<Integer>> res;
}

Q4.10  检查子树

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。

如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。

示例1:

 输入:t1 = [1, 2, 3], t2 = [2]
 输出:true
示例2:

 输入:t1 = [1, null, 2, 4], t2 = [3, 2]
 输出:false

思路:遍历二叉树t1的每一个节点,看能否找到以该节点为根的树与t2相同。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public static boolean isSame(TreeNode t1, TreeNode t2) {
        //当同时到达叶子节点的后继(都为空),依然没返回false,就返回true
        if (t1 == null && t2 == null) {
            return true;
        }
        //待比较的两个节点一个为空,另一个不为空,说明这两棵树不相等
        if (t1 == null || t2 == null) {
            return false;
        }
        //如果待比较的两个节点都不为空,就比较它们的值是否相等,如果值相等就继续判断它们的左、右子树是否相等
        return t1.val == t2.val && isSame(t1.left, t2.left) && isSame(t1.right, t2.right);
    }
    public boolean checkSubTree(TreeNode t1, TreeNode t2) {
        //如果遍历到达的节点为空,则判断t2是否也为空,若是返回true,不是返回false
        if (t1 == null) {
            return t2 == null;
        }
        //遍历t1的每一个节点,看能否找到一棵子树与t2相同
        return isSame(t1, t2) || (checkSubTree(t1.left, t2) || checkSubTree(t1.right, t2));
    }
}

Q4.12  求和路径

给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。

示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回:

3
解释:和为 22 的路径有:[5,4,11,2], [5,8,4,5], [4,11,7]

class Solution {

    public int pathSum(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }
        return helper(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
    }

    private int helper(TreeNode node, int sum) {
        if (null == node) {
            return 0;
        }
        sum -= node.val;
        int count = sum == 0 ? 1 : 0;
        count += helper(node.left, sum);
        count += helper(node.right, sum);
        return count;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值