【leetcode】中关于二叉树的那些题

112 Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

Note: A leaf is a node with no children.

Example:

Given the below binary tree and sum = 22,
         5
      /    \
    4       8
    /        / \
11       13   4
/   \               \
7    2              1

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

思路:

判断二叉树的根结点到某一叶子结点的路径是否等于给定值,有返回true,没有返回false
一般对于二叉树的题,通常用递归来解决,因为二叉树本身就是一个递归结构。
1.如果遍历的结点为空,返回false
2.如果遍历的结点是叶子结点,则将目前的路径和+当前结点的值,判断当前路径和是否等于给定的路径和,等于返回true,不等于返回false
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 hasPathSum(TreeNode root, int sum) {
        if(root == null)
            return false;
        return hasPathCore(root,sum,0);
    }
    private boolean hasPathCore(TreeNode root,int tarSum,int currSum){
        if(root == null)
            return false;
        currSum += root.val;
        boolean isLeaf = root.left == null && root.right == null;
        //叶结点
        if(isLeaf){
            //等于目标和,返回true,否则返回false
            if(currSum == tarSum)
                return true;
            else
                return false;
        }
        //左子树或者右子树找到一条路径就可以
        return hasPathCore(root.left,tarSum,currSum) || hasPathCore(root.right,tarSum,currSum);

    }
}

113 Path Sum II

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

Note: A leaf is a node with no children.

Example:

Given the below binary tree and sum = 22,
         5
      /    \
    4       8
    /        / \
11       13   4
/   \               \
7    2              1
Return:

[
[5,4,11,2],
[5,8,4,5]
]

思路:

上一道题加了一点难度,就是要找出满足目标和的路径
主要的思路没有变,就是在寻找路径的过程中需要将符合条件的路径加入到path中

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.*;
class Solution {
    List<List<Integer>> paths = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<Integer> path = new ArrayList<>();
        if(root == null)
            return paths;
        hasPathCore(root,sum,0,path);
        return paths;
    }
    private void hasPathCore(TreeNode root,int tarSum,int currSum,List<Integer> path){
        if(root == null)
            return;
        currSum += root.val;
        path.add(root.val);
        boolean isLeaf = root.left == null && root.right == null;
        if(isLeaf){
            if(currSum == tarSum){
                //找到一条路径,加入paths中
                paths.add(path);
            }else
                return;
        }
        //接下来是分别找该结点的左子树中、右子树中是否有符合条件的
        //由于list是引用传递,为了在深度遍历寻找中不影响当前的结果,所以创建一个新的List传递当前已经找到的路径
        hasPathCore(root.left,tarSum,currSum,new ArrayList<>(path));
        hasPathCore(root.right,tarSum,currSum,new ArrayList<>(path));
    }
}

235.Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

     _______6______
    /              \
 __2__           __8__
/      \        /      \
0       4       7       9
       /  \
       3   5

For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

思路:

此题是求二叉搜索树中两个结点的最低公共祖先,其中结点可以作为结点自身的最低公共祖先。
根据二叉有序树性质
1.从根结点开始遍历,如果当前结点的值均大于两个结点的值,那么两个结点的最低公共祖先一定位于当前结点的左子树
2.如果均小于两个结点的值,那么必定位于当前结点的右子树
3.当前结点值大于一个结点而小于另一个结点,那么即找到了最低公共祖先

/**
 * 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 || root == p || root == q)
            return root;
        while(root != null){
            int curr = root.val;
            int max = Math.max(p.val,q.val);
            int min = Math.min(p.val,q.val);
            if(curr > max){
                root = root.left;
            }else if(curr < min)
                root = root.right;
            else
                return root;
        }
        return null;
    }
}

另一种实现思路:
首先找到从根结点到两个结点的路径,记录到集合中,然后在两个集合中寻找最低公共祖先,也就是两个结合的最后一个相等的结点

    public TreeNode findLowestAncestor(TreeNode root,TreeNode n1,TreeNode n2){
        if (root == null || root == n1 || root == n2)
            return root;
        List<TreeNode> path1 = new ArrayList<>();
        List<TreeNode> path2 = new ArrayList<>();
        GetNodePath(root,n1,path1);
        GetNodePath(root,n2,path2);
        TreeNode common = null;
        for (int i = 0; i < path1.size() && i < path2.size(); i++) {
            if (path1.get(i) == path2.get(i))
                common = path1.get(i);
            else
                break;
        }
        return common;
    }
    /**
     * 寻找到该结点的路径
     * 本质上还是先序遍历
     * 如果当前节点是目标结点,直接返回;
     * 否则遍历其左孩子结点,加入路径path,递归查找,如果未找到,移除加入的左孩子结点;
     * 最后遍历其右孩子结点,加入路径path,递归查找
     */
    private boolean GetNodePath(TreeNode root,TreeNode node,List<TreeNode> path){
        if (root == node)
            return true;
        if (root.left != null){
            path.add(root.left);
            if (GetNodePath(root.left,node,path))
                return true;
            path.remove(path.size() - 1);
        }
        if (root.right != null){
            path.add(root.right);
            if (GetNodePath(root.right,node,path))
                return true;
            path.remove(path.size() - 1);
        }
        return false;
    }

236.Lowest Common Ancestor of a Binary Tree

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

     _______3______
    /              \
 __5__           __1__
/      \        /      \
6       2       0       8
       /  \
      7    4

For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

思路:

给定任意二叉树,找出其中两个结点的公共祖先
由于不是二叉搜索树,所以无法根据二叉树的性质遍历
1.当前结点为空,返回Null
2.如果当前的结点值等于两个结点中的任意一个,则当前的结点即为找到的最低公共祖先(因为我们从上往下遍历,所以另一个不等的结点必定在该结点下面)
3.如果不等于,然后我们分别在当前结点的左子树,右子树中重复上述两个操作寻找这两个结点
4.如果左右子树中均找到了,即left和right均不为空,那么当前的root即为最低公共祖先;如果有一个没找到,那么可以断定两个结点必定是位于当前结点的左子树或者全部位于右子树,其中返回的不为空的结点即为最低公共祖先

 public TreeNode lowestCommonAncestor(TreeNode root,
                              TreeNode p, TreeNode q) {
        if(root == null)
            return null;
        if(root == p || root == q)
            return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left != null && right != null)
            return root;
        return left == null ? right : left;
}

114.Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

For example, given the following tree:

     1
    / \
   2   5
  / \   \
  3   4   6

The flattened tree should look like:

1
 \
    2
      \
        3
          \
            4
              \
                5
                   \
                      6

思路:
将二叉树转变为只有右孩子结点的二叉树,其中我们可以发现右孩子结点的序列就是前序遍历的结果,那么在转换的时候,我们从最后遍历的结点向前开始修正结点的顺序。
最简洁的递归实现:
1.当前结点为空,return
2.递归右子树,左子树,那么最终的结果就是找到最右叶子结点
3.找到最右叶子结点也就是最后的结点,修改其左右孩子指针指向null 和前一个遍历的结点,也就是我们是从右、左、根的顺序递归遍历
4.更新前一个遍历的结点为当前结点,返回上一层递归

private TreeNode prev = null;
public void flatten(TreeNode root) {
    if (root == null)
        return;
    flatten(root.right);
    flatten(root.left);
    root.right = prev;
    root.left = null;
    prev = root;
}

不用递归,利用栈实现
最终序列实际是先根后左孩子结点最后右孩子结点的顺序,那么入栈时,应该先让右孩子结点入栈,然后左孩子结点入栈

public void flatten(TreeNode root) {
        if(root == null) return;
        Stack<TreeNode> s = new Stack<>();
        s.push(root);
        //记录前一个被遍历的结点,当前遍历的结点
        TreeNode prev = null, curr = null;
        while(!s.isEmpty()){
            //弹出栈顶元素
            curr = s.pop();
            //如果前一个遍历的结点不为空,即非根结点
            if(prev != null) {
                //前一个结点的右指针指向当前结点
                prev.right = curr; 
                prev.left=null;
            }
            //当前结点如果左右孩子不为空,则入栈
            if(curr.right != null) 
                s.push(curr.right);
            if(curr.left != null) 
                s.push(curr.left);
            //更新前一个遍历的结点
            prev = curr;
        }
        curr.right = null;
    }

199.Binary Tree Right Side View

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

Example:

Input: [1,2,3,null,5,null,4]
Output: [1, 3, 4]
Explanation:

       1     <—1
       / \
     2    3     <—3
       \     \
         5    4    <—4

思路:

其实就是每一层按照层序遍历
输出结果是每一层的最后一个元素
层序遍历,需要队列,同时因为要判断目前遍历的元素是否是该层的最后一个元素,所以需要记录每一层元素的个数,每次访问一个结点,就将元素个数-1,直到减为0,表示该层结点访问完毕,最后访问的结点就是该层的最后一个结点

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.*;
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> view = new ArrayList<>();
        Queue<TreeNode> q = new LinkedList<>();
        if(root == null)
            return view; 
        q.offer(root);
        int curr = 1;
        int next = 0;
        while(!q.isEmpty()){
            TreeNode node = q.poll();
            if(node.left != null){
                q.offer(node.left);
                next++;
            }
            if(node.right != null){
                q.offer(node.right);
                next++;
            }
            curr --;
            if(curr == 0){
                //更新curr值
                curr = next;
                //next即下一层结点数置0
                next = 0;
                view.add(node.val);
            }
        }
        return view;
    }
}
//别人家的代码
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null)
            return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int levelSize = queue.size();
            for(int i=0;i<levelSize;i++){
                TreeNode node = queue.poll();
                if(i == levelSize - 1)
                    result.add(node.val);
                if(node.left != null)
                    queue.offer(node.left);
                if(node.right != null)
                    queue.offer(node.right);
            }
        }
        return result;
    }
}

105.Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

For example, given

preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:

      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 TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || inorder == null || preorder.length != inorder.length)
            return null;
        return buildTreeCore(preorder,inorder);
    }
    private TreeNode buildTreeCore(int[] preorder,int[] inorder){
        if(preorder.length == 0 || inorder.length == 0)
            return null;
        TreeNode root = new TreeNode(preorder[0]);
        for(int i=0;i<inorder.length;i++){
            if(inorder[i] == preorder[0]){
                root.left = buildTreeCore(Arrays.copyOfRange(preorder,1,i+1),Arrays.copyOfRange(inorder,0,i));
                root.right = buildTreeCore(Arrays.copyOfRange(preorder,i+1,preorder.length),Arrays.copyOfRange(inorder,i+1,inorder.length));
                break;
            }
        }
        return root;
    }
}

106.Construct Binary Tree from Inorder and Postorder Traversal

Given inorder and postorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

For example, given

inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:

      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 TreeNode buildTree(int[] inorder, int[] postorder) {
        if(inorder == null || postorder == null 
        || inorder.length != postorder.length)
            return null;
        return buildTreeCore(inorder,postorder);
    }
    private TreeNode buildTreeCore(int[] inorder,int[] postorder){
        if(inorder.length == 0 || postorder.length == 0)
            return null;
        int len = postorder.length;
        TreeNode root = new TreeNode(postorder[len-1]);
        for(int i=0;i<inorder.length;i++){
            if(postorder[len-1] == inorder[i]){
                root.left =   buildTreeCore(Arrays.copyOfRange(inorder,0,i),
                Arrays.copyOfRange(postorder,0,i));
                root.right = buildTreeCore(Arrays.copyOfRange(inorder,i+1,inorder.length),
                Arrays.copyOfRange(postorder,i,len-1));
                break;
            }
        }
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值