二叉树

二叉树基础知识:可查看http://www.cnblogs.com/polly333/p/4740355.html
层序遍历:依靠队列,没有递归解法。可查看https://www.cnblogs.com/hapjin/p/5409921.html
前中后序遍历:依靠栈,有递归和非递归两种解法

1.求二叉树根到叶节点的最短距离

https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/description/
类似maximum-depth-of-binary-tree。不过注意,如果一个节点只有左子树或只有右子树。我们不能取左右子树中最短的,会取到0(叶子节点指的是没有子节点的节点),这样不符合题意。所以二者其一为空时,就取另一个的长度,最为最短长度。
递归解法:

/**
 * 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;
        }
        if(root.left==null){
            return minDepth(root.right)+1;
        }
        if(root.right==null){
            return minDepth(root.left)+1;
        }
        return Math.min(minDepth(root.right)+1,minDepth(root.left)+1);  
    }
}

非递归解法:用到了层序遍历。
根节点入队列。
然后在循环中判断队列非空时,弹出队列中的节点,并把节点的子节点入队列。
curNum用来记录一层的节点数。
lastNum记录这层还需要遍历的节点数。当lastNum为0时,说明这层已经遍历完,可以层数+1;
终止条件即为:找到了左右子树都为空的节点。
如果是求maximum-depth,则终止条件是queue为空==》即所有的节点都被遍历过。

/**
 * 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;
        LinkedList queue = new LinkedList();
        queue.add(root);
        int curNum = 0;
        int lastNum=1;
        int level=1;
        while(!queue.isEmpty()){
            TreeNode temp = queue.poll();
            lastNum--;
            if(temp.left==null&&temp.right==null){
                return level;
            }
            
            if(temp.left!=null){
                queue.add(temp.left);
                curNum++;
            }
            if(temp.right!=null){
                queue.add(temp.right);
                curNum++;
            }
            if(lastNum==0){
                lastNum=curNum;
                curNum=0;
                level++;
            }
        }
        return 0;
    }
}

要点:

  1. 递归解法:需要注意判断子节点左右节点其中一个为空的情况
  2. 非递归解法:用linkedList作为队列;记录层中节点数,遍历完一层,层数+1;

关于LinkedList

  1. poll()和pop()都是取first并删除,队列为空时前者返回null,后者返回NoSuchElementException。本质都是调用unLinkList()
  2. offer(),add()都是向队列中添加元素到末尾。offer调了add。返回值为true,实际调用linkLast()。
    push是添加元素到开头。实际调用linkFirst()。无返回值

2.求二叉树根到叶节点的最大距离

https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/
非递归解法

/**
 * 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;
        LinkedList queue = new LinkedList();
        queue.add(root);
        int curNum=0;
        int lastNum=1;
        int level =0;
        while(!queue.isEmpty()){
            TreeNode temp = queue.poll();
            lastNum--;
            if(temp.left!=null){
                queue.add(temp.left);
                curNum++;
            }
            if(temp.right!=null){
                queue.add(temp.right);
                curNum++;
            }
            if(lastNum==0){
                lastNum=curNum;
                curNum=0;
                level++;
            }
        }
        return level;  
    }
}

要点:这次的level初始值为0。原因就在于max不会提前判断叶子节点,叶子节点会走到最后level++的里面,所以不需要直接+1

3.对称二叉树的判断

https://leetcode-cn.com/problems/symmetric-tree/description/

递归解法

/**
 * 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 ST(root.left,root.right);
    }
    
    private boolean ST(TreeNode left,TreeNode right){
        if(left==null&&right==null)return true;
        else if(left==null||right==null)return false;
        else if(left.val!=right.val)return false;
        else{
            return ST(left.left,right.right)&&ST(left.right,right.left);
        }
    }
}

要点:递归式在于左树的左孩子和右树的右孩子判对称;左树的右孩子和右树的左孩子判对称。终止条件在于两边孩子都是null的时候,left.val=right.val即返回true。
时间复杂度: 本质其实就是DFS,时间复杂度为O(n)
空间复杂度: O(h)

迭代解法

利用两个队列来完成。
要点:对称树实际上是判断左树和右树是否对称。以根节点为中轴线,左边的存入leftQueue,右边的存入rightQueue;存入顺序记得对称,一一进行比对
注意:此处不能直接左右为空返回true,因为需要进一步的判断

/**
 * 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 ST(root);
    }
    
    private boolean ST(TreeNode root){
        if(root==null)return true;
        LinkedList leftQueue=new LinkedList();
        LinkedList rightQueue=new LinkedList();
        leftQueue.add(root.left);
        rightQueue.add(root.right);
        while(!leftQueue.isEmpty()&&!rightQueue.isEmpty()){
            TreeNode left=leftQueue.poll();
            TreeNode right=rightQueue.poll();
            if(left==null&&right==null)continue;
            else if(left==null&&right!=null||right==null&&left!=null)return false;
            else if(left.val!=right.val)return false;
            else{
                leftQueue.add(left.left);
                leftQueue.add(left.right);
                rightQueue.add(right.right);
                rightQueue.add(right.left);
            }
        }
        return true; 
    }
}

4.N叉树后序遍历

迭代解法:

1.用栈
2.打印条件是:没有孩子(最终节点)或者上一个节点是它的孩子(孩子节点打完,需要打印上层节点)
3.放入时从右向左放节点,与读取顺序相反
如果是前序遍历,则不需要if判断,直接pop打印即可

/*
// Definition for a Node.
class Node {
    public int val;
    public List children;

    public Node() {}

    public Node(int _val,List _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    public List postorder(Node root) {
        List resultList = new LinkedList();
        if(root==null)return resultList;
        Stack stack =new Stack();
        stack.push(root);
        Node pre=null;
        Node cur=null;
        while(!stack.isEmpty()){
            cur = stack.peek();
            if(pre!=null && cur.children.contains(pre) || cur.children.isEmpty()){
                resultList.add(cur.val);
                stack.pop();
                pre=cur;
            }else{
                int length=cur.children.size();
                for(int i=0;i

递归解法

dfs,会遍历到最下面的节点,然后打印。保证先打出来的就是最下层。而且是先遍历到左节点的最下层,才会遍历右节点。
如果是前序遍历,则把 res.add(root.val);提到for循环之前

class Solution {
     public void dfs(List res,Node root){
        if(root==null){
            return;
        }
        for(Node x:root.children){
            dfs(res,x);
        }
         res.add(root.val);
    }
    public List postorder(Node root)  {
        List res = new ArrayList();
        dfs(res,root);
        return res;
    }
}

5.中序遍历

要点:
1.使用栈
2.入栈当前节点,并将左子节点置为下个遍历节点。while循环结束时,所有的左子节点都入栈。
3.出栈时,pop节点打印。并将右子节点设为下个遍历节点。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List res = new LinkedList();
    public List inorderTraversal(TreeNode root) {
        if(root==null)return res;
        Stack stack = new Stack();
        TreeNode cur=root;
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }
            //取出节点,并把当前节点设成取出节点的右子节点
            if(!stack.isEmpty()){
                cur=stack.pop();
                res.add(cur.val);
                cur=cur.right;
            } 
        }
        return res;
    }
}

6.层次遍历

递归方式

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List> levelOrder(TreeNode root) {
        List> result = new ArrayList<>();
        set(root, 0, result);
        return result;
    }

    public void set(TreeNode treeNode, int level, List> result) {
        if(treeNode==null){
            return;
        }
        if(level==result.size()){
            result.add(new ArrayList<>());
        }
        result.get(level).add(treeNode.val);
        set(treeNode.left,level+1,result);
        set(treeNode.right,level+1,result);
    }
}

非递归方式

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List> res = new LinkedList>();
    public List> levelOrder(TreeNode root) {
        LinkedList queue = new LinkedList();
        if(root==null)return res;
        queue.add(root);
        int curNum=0;
        int lastNum=1;
        while(!queue.isEmpty()){
            List tempList = new LinkedList();
            while(lastNum!=0){
                TreeNode temp = queue.pop();
                tempList.add(temp.val);
                if(temp.left!=null){
                    queue.add(temp.left);
                    curNum++;
                }
                if(temp.right!=null){
                    queue.add(temp.right);
                    curNum++;
                }
                lastNum--;
            }
            lastNum=curNum;
            curNum=0;
            res.add(tempList);
        }
        return res;
    }
}

变形题:二叉树的右视图
https://leetcode-cn.com/problems/binary-tree-right-side-view/description/
只取每层的最后一个节点

7.翻转二叉树

https://leetcode-cn.com/problems/invert-binary-tree/description/
递归解法:
1.翻转左右节点
2.翻转左右子树

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

8.平衡二叉树的判断

递归方式:
用maximum-depth的方法求树高度。
判断根节点的左右两子树高度差是否大于1,若大于1则非平衡树,返回false;否则,继续递归的判断其左子树和右子树是否是平衡树。
这样做会重复遍历多次节点。求一个节点的深度是O(lgn),所以求所有节点的就是O(nlgn)。

/**
 * 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 left = treeDepth(root.left);
        int right = treeDepth(root.right);
        if(Math.abs(left-right)>1){
            return false;
        }
        return isBalanced(root.left)&&isBalanced(root.right);
    }
    private int treeDepth(TreeNode root){
        if(root==null)return 0;
        int left = treeDepth(root.left);
        int right= treeDepth(root.right);
        return Math.max(left,right)+1;
    }
}

上面那个方法正确但不是很高效,因为每一个点都会被上面的点计算深度时访问一次,我们可以进行优化。方法是如果我们发现子树不平衡,则不计算具体的深度,而是直接返回-1。那么优化后的方法为:对于每一个节点,我们通过checkDepth方法递归获得左右子树的深度,如果子树是平衡的,则返回真实的深度,若不平衡,直接返回-1,此方法时间复杂度O(N),空间复杂度O(H),参见代码如下:
要点在于计算高度的时候顺便算出是否平衡,同一个节点不需要遍历两次

/**
 * 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) {
        int height = checkDepth(root);
        if(height>=0){
            return true;
        }else{
            return false;
        }
        
    }
    private int checkDepth(TreeNode root){
        if(root==null)return 0;
        int left = checkDepth(root.left);
        int right= checkDepth(root.right);
        if(left==-1||right==-1)return -1;
        if(Math.abs(left-right)>1){
            return -1;
        }else{
            return Math.max(left,right)+1;
        }
    }
}

9.二叉树剪枝

https://leetcode-cn.com/problems/binary-tree-pruning/description/
思路:
1.如果本身为1,保留这个节点。对其左右节点进行剪枝
2.如果左右节点剪枝不为空,那么保留这个节点
3.如果左右节点剪枝为空,说明节点为0,左右节点剪枝结果为null,不保留这个节点

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode pruneTree(TreeNode root) {
        if(root==null)return null;
        TreeNode newRoot;
        TreeNode left = pruneTree(root.left);
        TreeNode right = pruneTree(root.right);
        if(root.val==1){
            newRoot = new TreeNode(root.val);
            newRoot.left = left;
            newRoot.right= right;
        }else if(left!=null||right!=null){
            newRoot = new TreeNode(root.val);
            newRoot.left = left;
            newRoot.right= right;
        }else{
            newRoot=null;
        }
        return newRoot;
        
    }
}

二叉搜索树

https://blog.csdn.net/qq_37887537/article/details/75647670

1.将有序数组转化为二叉搜索树

https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/description/
二叉搜索树按照中序遍历可得到有序数组;那么反之,我们可以得知,根节点是有序数组的中间节点,从中间节点分开左右两个有序数组,这两个有序数组的中间节点又分别为中间节点的左右子节点。这就是二分查找的中心思想啊。
思路:
用二分查找法,找到根节点,然后左子节点为左区间的中间节点;右子节点为右区间的中间节点。递归而成

/**
 * 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) {
        return midSortToBST(nums,0,nums.length-1);
    }
    private TreeNode midSortToBST(int[] nums,int left,int right){
        if(left>right)return null;
        int mid = (left+right)/2;
        TreeNode cur = new TreeNode(nums[mid]);
        cur.left = midSortToBST(nums,left,mid-1);
        cur.right = midSortToBST(nums,mid+1,right);
        return cur;
    }
}

2.二叉搜索树剪枝

https://leetcode-cn.com/problems/trim-a-binary-search-tree/description/
二叉搜索树不一定是平衡树。
思路:
1.如果root值小于L,则抛弃左子树,返回右子树的剪枝结果
2.如果root值大于R,则抛弃右子树,返回左子树的剪枝结果
3.如果root值介于L与R之间,则根为root的值,左右节点分别是左右子树的剪枝结果

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode trimBST(TreeNode root, int L, int R) {
        if(root==null)return null;
        if(root.valR){
            return trimBST(root.left,L,R);
        }else{
            TreeNode cur = new TreeNode(root.val);
            cur.left = trimBST(root.left,L,R);
            cur.right = trimBST(root.right,L,R);
            return cur;
        }
    }
}

你可能感兴趣的:(二叉树)