二叉树(二)

将二叉查找树变为有序的双向链表(不能创建新节点,只调整指针)

判断二叉树是不是平衡二叉树

二叉树中两个节点的最低公共祖先节点

二叉树的序列化和反序列化

由前序遍历和中序遍历构造二叉树

由中序遍历和后序遍历树构造二叉树

二叉树的所有路径

二叉树中和为某一值的路径

 

二叉树中和为某一值的路径

 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

public class Solution {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        ArrayList<ArrayList<Integer>> pathList = new ArrayList<ArrayList<Integer>>();
        
        if(root==null)
            return pathList;
        
        Stack<Integer> stack = new Stack<>();
        findPath(root, target, stack, pathList);
        return pathList;
    }
    
    
    private void findPath(TreeNode root, int target, Stack<Integer> path, 
                          ArrayList<ArrayList<Integer>> pathList){
        
        if(root==null)
            return;
        
        if(root.left==null && root.right==null){//叶子节点
            if(root.val == target){
                ArrayList<Integer> list = new ArrayList<>();
                for(int i: path){
                    list.add(i);
                }
                list.add(root.val);
                pathList.add(list);
            }
        }else{
            path.push(root.val);
            findPath(root.left, target-root.val, path, pathList);
            findPath(root.right, target-root.val, path, pathList);
            path.pop();
        }
        
    }
}

 

将二叉查找树变为有序的双向链表(不能创建新节点,只调整指针)

 递归

public TreeNode convertBST2DLLRec(TreeNode root) {
    root = convertBST2DLLSubRec(root);
    // 递归完,root会在链表的中间位置,要把root移到链表头
    while (root.left != null) {
        root = root.left; 
    }
    return root;
}
private TreeNode convertBST2DLLSubRec(TreeNode root) {
    if (root == null || (root.left == null && root.right == null)) {
        return root;
    }

    TreeNode tmp = null;
    if (root.left != null) { // 处理左子树
        tmp = convertBST2DLLSubRec(root.left);
        while (tmp.right != null) { // 寻找最右节点
            tmp = tmp.right;
        }
        tmp.right = root; // 把左子树最右节点和root连接
        root.left = tmp;
    }
    if (root.right != null) { // 处理右子树
        tmp = convertBST2DLLSubRec(root.right);
        while (tmp.left != null) { // 寻找最左节点
            tmp = tmp.left;
        }
        tmp.left = root; // 把右子树最左节点和root连接
        root.right = tmp;
    }
    return root;
}

 非递归

// 类似inorder traversal
public TreeNode convertBST2DLL(TreeNode root) {
    if (root == null) {
        return null;
    }

    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode cur = root; // 指向当前处理节点
    TreeNode old = null; // 指向前一个处理的节点
    TreeNode head = null; // 链表头

    while (true) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }

        if (stack.isEmpty()) {
            break;
        }

        cur = stack.pop();

        if (old != null) {
            old.right = cur;
        }
        if (head == null) {
            head = cur;
        }
        old = cur; // 更新old
        cur = cur.right;
    }
    return head;
}

判断二叉树是不是平衡二叉树

 递归

public boolean isAVLRec(TreeNode root) {
    if (root == null) {
        return true;
    }

    // 如果左子树和右子树高度相差大于1,则非平衡二叉树, getDepthRec()是前面实现过的求树高度的方法
    if (Math.abs(getDepthRec(root.left) - getDepthRec(root.right)) > 1) {
        return false;
    }

    return isAVLRec(root.left) && isAVLRec(root.right);
}

二叉树中两个节点的最低公共祖先节点

 递归

/**
 *  求二叉树中两个节点的最低公共祖先节点 递归解法: 
 * (1)如果两个节点分别在根节点的左子树和右子树,则返回根节点
 * (2)如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
 */
public TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2) {
    if (findNodeRec(root.left, n1)) { // 如果n1在树的左子树
        if (findNodeRec(root.right, n2)) { // 如果n2在树的右子树
            return root; // 返回根节点
        } else { // 如果n2也在树的左子树
            return getLastCommonParentRec(root.left, n1, n2);
        }
    } else { // 如果n1在树的右子树
        if (findNodeRec(root.left, n2)) { // 如果n2在左子树
            return root;
        } else { // 如果n2在右子树
            return getLastCommonParentRec(root.right, n1, n2);
        }
    }
}

// 帮助方法,递归判断一个节点是否在树里
private static boolean findNodeRec(TreeNode root, TreeNode node) {
    if (root == null || node == null) {
        return false;
    }
    if (root == node) {
        return true;
    }
    boolean found = findNodeRec(root.left, node);
    if (!found) {
        found = findNodeRec(root.right, node);
    }
    return found;
}

 非递归

/**
 * 求二叉树中两个节点的最低公共祖先节点 非递归解法: 
 * 先求从根节点到两个节点的路径,然后再比较对应路径的节点,
 * 最后一个相同的节点就是二叉树中的最低公共祖先节点
 */
public TreeNode getLastCommonParent(TreeNode root, TreeNode n1, TreeNode n2) {
    if (root == null || n1 == null || n2 == null) {
        return null;
    }

    ArrayList<TreeNode> path1 = new ArrayList<TreeNode>();
    boolean res1 = getNodePath(root, n1, path1);
    ArrayList<TreeNode> path2 = new ArrayList<TreeNode>();
    boolean res2 = getNodePath(root, n1, path2);

    if (!res1 || !res2) {
        return null;
    }

    TreeNode last = null;
    Iterator<TreeNode> ite1 = path1.iterator();
    Iterator<TreeNode> ite2 = path2.iterator();

    while (ite1.hasNext() && ite2.hasNext()) {
        TreeNode tmp1 = ite1.next();
        TreeNode tmp2 = ite2.next();
        if (tmp1 == tmp2) {
            last = tmp1;
        } else {
            break;
        }
    }
    return last;
}

// 帮助方法 把从根节点到node节点路径上所有的点都添加到path中
private boolean getNodePath(TreeNode root, TreeNode node, ArrayList<TreeNode> path) {
    if (root == null) {
        return false;
    }

    path.add(root); // 把这个节点加到路径中
    if (root == node) {
        return true;
    }

    boolean found = false;
    found = getNodePath(root.left, node, path); // 先在左子树中找
    if (found == false) { // 如果没找到,再在右子树找
        found = getNodePath(root.right, node, path);
    }
    if (!found) { // 如果都没找到,证明这个节点不在路径中,说明刚才添加进去的不是路径上的节点,删掉
        path.remove(root);
    }

    return found;
}

 二叉树的序列化和反序列化

将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构

public String serialize(TreeNode root) {
    if( root == null)
        return "{}";
    ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
    queue.add(root);
    // 将二叉树的个节点按照从上到下、从左到有的存储在queue中
    for(int i=0;i<queue.size();i++){
        TreeNode q = queue.get(i);
        if(q== null)
            continue;
        queue.add(q.left);
        queue.add(q.right);
    }
    // 去除叶子节点的左右孩子,这个孩子是空值
    while(queue.get(queue.size() - 1) == null){
        queue.remove(queue.size() - 1);
    }
    // 遍历queue把转换成字符串
    StringBuilder sb = new StringBuilder();
    sb.append("{");
    sb.append(queue.get(0).val);
    for(int i=1;i<queue.size(); i++){
        TreeNode q = queue.get(i);
        if(q!= null){
            sb.append(",");
            sb.append(q.val);
        }else{
            sb.append(",#");
        }
    }
    sb.append("}");
    return sb.toString();
}

public TreeNode deserialize(String data) {
    if(data == "{}")
        return null;
    // 以逗号分割
    String[] vals = data.substring(1,data.length()-1).split(",");
    ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
    // 根节点 
    TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
    queue.add(root);
    int index = 0;
    boolean isLeftChild = true;
    for (int i = 1; i < vals.length; i++) {
        if (!vals[i].equals("#")) {
            TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
            if (isLeftChild) {
                queue.get(index).left = node;
            } else {
                queue.get(index).right = node;
            }
            queue.add(node);
        }
        if (!isLeftChild) {
            index++;
        }
        isLeftChild = !isLeftChild;
    }
    return root;
}

 

由前序遍历和中序遍历构造二叉树

/**
 * 前序遍历的第一个结点是root结点, 
 * 再从中序遍历中找到这个root结点,则root左边的就是左子树,root右边的就是右子树
 * 再递归处理
 */
public TreeNode buildTree(int[] preorder, int[] inorder) {
    TreeNode root = null;
    int[] leftPreorder;
    int[] rightPreorder;
    int[] leftInorder;
    int[] rightInorder;

    int preorderPos;
    int inorderPos;

    if (preorder.length != 0 && inorder.length != 0) {
        root = new TreeNode(preorder[0]);

        // 把中序遍历分成两个子树
        inorderPos = findPosition(inorder, 0, inorder.length - 1, preorder[0]);
        leftInorder = Arrays.copyOfRange(inorder, 0, inorderPos);
        rightInorder = Arrays.copyOfRange(inorder, inorderPos + 1, inorder.length);

        // 把前序遍历分成两个子树
        preorderPos = leftInorder.length;
        leftPreorder = Arrays.copyOfRange(preorder, 1, 1 + preorderPos);
        rightPreorder = Arrays.copyOfRange(preorder, 1 + preorderPos, preorder.length);

        root.left = buildTree(leftPreorder, leftInorder);
        root.right = buildTree(rightPreorder, rightInorder);
    }
    return root;
}

private int findPosition(int[] inorder, int istart, int iend, int r) {
    for (int i = istart; i <= iend; i++)
        if (inorder[i] == r)
            return i;
    return -1;
}

 

 由中序遍历和后序遍历树构造二叉树

/**
 * 后序遍历的最后一个结点是root结点, 
 * 再从中序遍历中找到这个root结点,则root左边的就是左子树,root右边的就是右子树
 */
public TreeNode buildTree(int[] inorder, int[] postorder) {
    TreeNode root = null;
    int[] leftPostorder;
    int[] rightPostorder;
    int[] leftInorder;
    int[] rightInorder;

    int postorderPos;
    int inorderPos;

    if (inorder.length != 0 && postorder.length != 0) {
        root = new TreeNode(postorder[postorder.length - 1]);

        // 中序遍历 分成两个子树
        inorderPos = findPosition(inorder, postorder[postorder.length - 1]);
        leftInorder = Arrays.copyOfRange(inorder, 0, inorderPos);
        rightInorder = Arrays.copyOfRange(inorder, inorderPos + 1, inorder.length);

        // 后序遍历分成两个子树
        postorderPos = leftInorder.length;
        leftPostorder = Arrays.copyOfRange(postorder, 0, postorderPos);
        rightPostorder = Arrays.copyOfRange(postorder, postorderPos, postorder.length - 1);

        root.left = buildTree(leftInorder, leftPostorder);
        root.right = buildTree(rightInorder, rightPostorder);
    }
    return root;
}

private int findPosition(int[] arr, int r) {
    for (int i = 0; i <= arr.length; i++)
        if (arr[i] == r)
            return i;
    return -1;
}

 

二叉树的所有路径

public List<String> binaryTreePaths(TreeNode root) {
    List<String> result = new ArrayList<>();
    if(root == null){
        return result;
    }
    String path = "";
    paths(result, root, path);
    return result;
}

private void paths(List<String> result, TreeNode root, String path){
    if(root == null){
        return;
    }
    // 叶子节点
    if(root.left == null && root.right == null){
        if(path == ""){
            path += root.val;
        }else{
            path = path + "->" + root.val;
        }
        result.add(path);
        return;
    }
    
    if(path == ""){
        path += root.val;
    }else{
        path = path + "->" + root.val;
    }
    
    paths(result, root.left, path);
    paths(result, root.right, path);
}

 

二叉树中相距最远的两个节点之间的距离

 递归

 

posted @ 2016-06-10 15:43  Hesier  阅读(171)  评论(0编辑  收藏  举报