二叉树

二叉树基础知识:可查看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<TreeNode> queue = new LinkedList<TreeNode>();
        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<TreeNode> queue = new LinkedList<TreeNode>();
        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<TreeNode> leftQueue=new LinkedList<TreeNode>();
        LinkedList<TreeNode> rightQueue=new LinkedList<TreeNode>();
        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<Node> children;

    public Node() {}

    public Node(int _val,List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    public List<Integer> postorder(Node root) {
        List<Integer> resultList = new LinkedList<Integer>();
        if(root==null)return resultList;
        Stack<Node> stack =new Stack<Node>();
        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<cur.children.size();i++){
                    stack.push(cur.children.get(length-i-1));
                }
            }
        }
        return resultList;
    }
}

递归解法

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

class Solution {
     public void dfs(List<Integer> res,Node root){
        if(root==null){
            return;
        }
        for(Node x:root.children){
            dfs(res,x);
        }
         res.add(root.val);
    }
    public List<Integer> postorder(Node root)  {
        List<Integer> res = new ArrayList<Integer>();
        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<Integer> res = new LinkedList<Integer>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null)return res;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        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<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        set(root, 0, result);
        return result;
    }

    public void set(TreeNode treeNode, int level, List<List<Integer>> 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<List<Integer>> res = new LinkedList<List<Integer>>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        if(root==null)return res;
        queue.add(root);
        int curNum=0;
        int lastNum=1;
        while(!queue.isEmpty()){
            List<Integer> tempList = new LinkedList<Integer>();
            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.val<L){
            return trimBST(root.right,L,R);
        }else if(root.val>R){
            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;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,348评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,122评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,936评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,427评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,467评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,785评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,931评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,696评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,141评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,483评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,625评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,291评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,892评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,492评论 2 348

推荐阅读更多精彩内容