leetcode二叉树整理1

那说到二叉树,肯定先说到的就是前中后序遍历
下面这个是一个简单的二叉树节点定义

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

144.二叉树的前序遍历

递归方式:
思路:递归很好写啊,在压递归栈的时候,前中后遍历的区别就只有,中间节点在什么位置被加入list中

class Solution {
    
    
    public List<Integer> preorder(TreeNode root,List<Integer> list){
    
    
        if(root == null) return list;
        list.add(root.val);
        list = preorder(root.left,list);
        list = preorder(root.right,list);
        return list;

    }
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new LinkedList<Integer>();
        list = preorder(root,list);
        return list;
    }
}

迭代:
思路:需要使用一个栈,将节点依次放入到栈中,首先将根节点放入栈中,然后开始循环,每次循环中,将栈顶元素出栈,如果获取的元素不为空,那么,先输出该节点值,然后依次将该节点的右孩子,左孩子压入栈中(为啥是这个顺序?因为栈后进先出,左孩子后进,所以左孩子先出)

class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new LinkedList<Integer>();
        Deque<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offerLast(root);
        while(queue.size()!=0){
    
    
            TreeNode node = queue.pollLast();
            if(node!=null){
    
    
                list.add(node.val);
                queue.offerLast(node.right);
                queue.offerLast(node.left);
            }
        }
        return list;
    }
}

145.二叉树的后序遍历

递归:
思路:同前序遍历,只不过是中间节点加入的位置不同

class Solution {
    
    
    public List<Integer> postorder(TreeNode root,List<Integer> list){
    
    
        if(root == null) return list;
        
        list = postorder(root.left,list);
        list = postorder(root.right,list);
        list.add(root.val);
        return list;
    }

    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new LinkedList<Integer>();
        list = postorder(root,list);
        return list;
    }
}

迭代:
思路:后序遍历是左右中,但是中节点如果是迭代然后放到最后入队的话有点不太好处理,但是,如果把后序遍历的结果倒过来,大家会发现变成了中右左,那么跟前序遍历是一样的,直接使用前序遍历的算法,把循环中左右孩子亚展的顺序换一下就行了。

class Solution {
    
        
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        List<Integer> list = new LinkedList<Integer>();
        deque.offerLast(root);
        while(deque.size()!=0){
    
    
            TreeNode node = deque.pollLast();
            if(node!=null){
    
    
                list.add(node.val);
                deque.offerLast(node.left);
                deque.offerLast(node.right); 
            }
        }
        Collections.reverse(list);
        return list;
    }
}

94.二叉树的中序遍历

中序遍历递归还是一样简单,难点在于迭代
递归:
思路:同前序遍历,只不过是中间节点加入的位置不同

class Solution {
    
    
     public void postorder(TreeNode root,List<Integer> list){
    
    
        if(root == null) return; 
        postorder(root.left,list);
        list.add(root.val);
        postorder(root.right,list);

    }

    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new LinkedList<Integer>();
        postorder(root,list);
        return list;
    }
}

迭代中序遍历:
思路:这个跟前序后序的思路都不同,首先,进入一个while循环,这个循环的目的是,如果当前节点有左节点,将自身入栈,变成左节点,如果该节点为空,说明已经是没有左节点了,将栈中最后一个元素出栈,将该元素加入输出队列(因为这个元素没有左了啊,那么左中右就变成中右,肯定是这个元素先输出啦),然后将右节点入队,然后继续循环,知道循环不能继续为止

class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
       Deque<TreeNode> deque = new LinkedList<>();
       List<Integer> res = new LinkedList<>();
       TreeNode cur = root;
       while(deque.size()!=0||cur!=null){
    
    
           if(cur!=null){
    
    
               deque.offerLast(cur);
               cur = cur.left;
            }else{
    
    
                cur = deque.pollLast();
                res.add(cur.val);
                cur=cur.right;
           }
       }
       return res;
    }
}

102.二叉树的层序遍历

太经典了
思路:队列,在循环中,每次出队一个,然后它依次将左右孩子入队,最后自己加入输出队列中,为了应对空指针异常,在加入左后孩子的时候判断下
leetcode上该题的层序遍历结果要按层来输出,那就是有两个队列,首先第一个队列中只有root节点,第二节队列为空,然后第一个队列中的节点左右孩子要入队的时候,放入到第二个队列中,在循环结束之后一二队列值互换,这样就是有层次的层次遍历了

class Solution {
    
    
    public List<List<Integer>> levelOrder(TreeNode root) {
    
    
        List<List<Integer>> result = new LinkedList<List<Integer>>();
        Deque<TreeNode> queue = new LinkedList<TreeNode>();
        if(root==null) return result;
        queue.offerLast(root);
        while(queue.size()!=0){
    
    
            Deque<TreeNode> tmp = new LinkedList<TreeNode>();
            List<Integer> result_list = new LinkedList<Integer>();
            while(queue.size()!=0){
    
    
                TreeNode node = queue.pollFirst();
                result_list.add(node.val);
                if(node.left!=null) tmp.offerLast(node.left);
                if(node.right!=null) tmp.offerLast(node.right);
            }
            queue = tmp;
            result.add(result_list);
        }
        return result;
    }
}

107. 二叉树的层序遍历 II

给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
这个将上一题中拿到的reslut数组翻转一下就好了

199. 二叉树的右视图

上上题中reslut是List<List<Integer>>所以循环reslut,每次循环拿到一个List<Integer>,每次取这个List中的最后一个值即可构成答案,左视图也是同理,不要试图去尝试用什么遍历方法,针对不同结构的二叉树,用遍历太复杂了,要考虑的东西太多

637.二叉树的层平均值

同理,处理这个List<List<Integer>>的reslut即可

429.N叉树的层序遍历

与层序遍历同理,只是一个节点有多个孩子,在加入队列的时候要遍历孩子列表

226.翻转二叉树

思路:递归法:前序或后序遍历二叉树,然后将输出结果操作变成翻转操作就行了
注:不能用中序遍历

class Solution {
    
    
    
    public TreeNode invertTree(TreeNode root) {
    
    
        if(root == null) return null;
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);
        root.left = right;
        root.right = left;
        return root;
    }
}

迭代:同迭代的前序或后序遍历二叉树写法,然后将输出结果操作变成翻转操作就行了,又练了一遍写迭代遍历

class Solution {
    
    
    public TreeNode invertTree(TreeNode root) {
    
    
        if(root == null) return root;
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offerLast(root);
        TreeNode roottemp = root;
        TreeNode cur;
        TreeNode tmp;
        while(deque.size()!=0){
    
    
            cur = deque.pollLast();
            tmp = cur.right;
            cur.right = cur.left;
            cur.left = tmp;
            if(cur.right!=null) deque.offerLast(cur.right);
            if(cur.left!=null) deque.offerLast(cur.left);
        }
        return roottemp;
    }
}

101. 对称二叉树

是否对称,就是判断,这个两个节点值是否相同,并且两个节点A,B,A左子树和B右子树对称,A右子树和B左子树对称
或者更简单易懂的就是,使用相反顺序遍历A B,如果发现遍历结果相同,则AB为对称

递归:注意节点为空的判断条件 避免出现空指针异常

class Solution {
    
    
    public boolean isSymmetric(TreeNode root) {
    
    
        return check(root,root);
    }
    public boolean check(TreeNode p, TreeNode q){
    
    
        if(p==null&&q==null){
    
    
            return true;
        }else if(p==null||q==null){
    
    
            return false;
        }
        if (p.val==q.val && check(p.left,q.right) && check(p.right,q.left)){
    
    
            return true;
        }
        return false;
    } 
}

104. 二叉树的最大深度

思路:
递归:就是root节点左子树深度和右子树深度的最大值+1呗,然后左右子树深度,再去依法递归计算
迭代:层序遍历之后,计算reslut的长度即可

class Solution {
    
    
    public int maxDepth(TreeNode root) {
    
    
        if(root == null) return 0;
        return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }
}

559. N 叉树的最大深度

与上题同理

111.二叉树的最小深度

这道题,层次遍历很好想而且不递归
首先是分层去遍历二叉树,如果在这一层中找到一个节点左右孩子都为空,结束层次遍历,返回这是第几层即可

class Solution {
    
    
    public int minDepth(TreeNode root) {
    
    
        if(root==null) return 0;
        int depth = 0;
        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        deque.offerLast(root);
        while(deque.size()!=0){
    
    
            int size = deque.size(); 
            depth++;
            int flag=0;
            for(int i=0;i<size;i++){
    
    
                TreeNode node = deque.pollFirst();
                if(node.left!=null) deque.offerLast(node.left);
                if(node.right!=null) deque.offerLast(node.right);
                if(node.left==null&&node.right==null){
    
    
                    flag=1;
                    break;
                }
            }
            if(flag==1) break;
        }
        return depth;
    }
}

222.完全二叉树的节点个数

思路:层序遍历,遍历到倒数第二层的时候,记录是哪个节点的哪边(左孩子还是右孩子没了),然后,去计算就行了,当然直接层序遍历到底然后直接统计个数也行

class Solution {
    
    
    public int countNodes(TreeNode root) {
    
    
        if(root==null) return 0;
        int depth = 0;
        int count = 0;
        int flag=0; 
        Deque<TreeNode> deque = new LinkedList<TreeNode>();
        deque.offerLast(root);
        while(deque.size()!=0){
    
    
            int size = deque.size(); 
            depth++;                       
            for(int i=0;i<size;i++){
    
    
                TreeNode node = deque.pollFirst();
                if(node.left==null){
    
    
                    flag = 1;
                    count = i;
                    break;
                } 
                if(node.right == null){
    
    
                    flag = 2;
                    count = i;
                    break;
                }
                deque.offerLast(node.left);
                deque.offerLast(node.right);    
            }
            if(flag!=0) break;
        }
        return (int)Math.pow(2,depth)+count*2+flag-2;
    }
}

110.平衡二叉树

如果一个节点,左子树为平衡二叉树,右子树也为平衡二叉树,且左右子树高度差不超过1,则该节点形成的树为平衡二叉树,所以根据这个条件我们可以写出递归来,两个函数,一个计算树高度,一个判断树高度差是否小于1,并返回相应的boolean值

class Solution {
    
    
    public int depth(TreeNode node){
    
    
        if(node == null) return 0;
        return Math.max(depth(node.left),depth(node.right))+1;
    }
    public boolean balanced(TreeNode root) {
    
    
        if(root==null) return true;        
       if(Math.abs(depth(root.left)-depth(root.right))>=2) return false;
       return true;
    }
    public boolean isBalanced(TreeNode root) {
    
    
        if(root==null) return true;
        return balanced(root)&&isBalanced(root.left)&&isBalanced(root.right);
    }
}

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。
思路:这个题是不是用回溯会好一点
写回溯算法模板如下:1.外露在类中的指示当前回溯元素的元素集,一个最后主函数返回的结果集
2.在回溯函数中,最开头就是如果达到什么条件,该元素集对应结果进入结果集,然后是剪枝,达到什么条件,这一支整个减掉,如果遇到这俩情况,做完操作后函数直接返回
3.如果不满足上述条件,就将节点进入结果集,然后再将节点退出结果集

 	findPath(node.left);
	list.pollLast();

比如这两句,大家一看到可能会说为啥要进入又退出,实际上在第一句话内,已经将这个节点后面的所有可能性递归完了,然后退出这个节点,让下一个合理的节点进入,好去继续递归
递归实际上就是构建了一个完整的树,如果树节点满足条件,就加入结果集或者被剪掉。

class Solution {
    
    
    Deque<Integer> list = new LinkedList<Integer>();
    List<String> result = new LinkedList<String>();
    public void findPath(TreeNode node){
    
    
        if(node.left==null&&node.right==null){
    
    
            String spath = "";
            Iterator<Integer> it = list.iterator();
            while(it.hasNext()){
    
    
                spath += Integer.toString(it.next())+"->";
            }
            spath +=Integer.toString(node.val);
            list.offerLast(node.val);
            result.add(spath);
            return;
        }
        list.offerLast(node.val);
        if(node.left!=null){
    
    
            findPath(node.left);
            list.pollLast();
        }
        if(node.right!=null){
    
    
            findPath(node.right);
            list.pollLast();
        }
    }
    public List<String> binaryTreePaths(TreeNode root) {
    
    
        if(root==null) return result;
        findPath(root);
        return result;
    }
}

100. 相同的树

思路:如果两个树,节点值相同,并且左子树右子树都相同,则相同,很容易能够写出递归

572. 另一个树的子树

思路:先把判断相同树的代码粘过来,然后那么就是遍历这个大树,然后依次看,是否有一个大树的节点,该节点形成的树与小树相同即可

class Solution {
    
    
    public boolean isSametree(TreeNode s,TreeNode t){
    
    
        if(s==null&&t==null){
    
     
            return true;
        }else if(s==null||t==null){
    
    
            return false;
        }else if(s.val==t.val&&isSametree(s.left,t.left)&&isSametree(s.right,t.right)){
    
    
            return true;
        }
        return false;
    }
    public boolean isSubtree(TreeNode s, TreeNode t) {
    
    
        if(s==null&&t==null){
    
     
            return true;
        }else if(s==null||t==null){
    
    
            return false;
        }else if(s.val==t.val&&isSametree(s.left,t.left)&&isSametree(s.right,t.right)){
    
    
            return true;
        }else return isSubtree(s.left,t)||isSubtree(s.right,t);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38857307/article/details/114292231