【leetcode二叉树——二叉树遍历】

1. leetcode144 二叉树的前序遍历

2. leetcode94 二叉树的中序遍历

3. leetcode145 二叉树的后序遍历

4. leetcode102 二叉树的层序遍历

5. leetcode107 二叉树的层序遍历II

6. leetcode104 二叉树的最大深度

7. leetcode543 二叉树的直径

8. leetcode110 平衡二叉树

9. leetcode111 二叉树的最小深度

10. leetcode404 左叶子之和

解法一:前序遍历

class Solution {
    private int sum = 0;
    public int sumOfLeftLeaves(TreeNode root) {
        preOrder(root, root);
        return sum;
    }
    private void preOrder(TreeNode node, TreeNode parent){
        if(node == null)
            return;
        //判断其为左叶子节点
        if(node.left == null && node.right == null && parent.left == node){
            sum += node.val;
        }
        preOrder(node.left, node);
        preOrder(node.right, node);
    }
}

解法二:后序遍历

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        return postOrder(root, root);
    }

    private int postOrder(TreeNode node, TreeNode parent){
        if(node == null)
            return 0;
        if(node.left == null && node.right == null && parent.left == node){
            return node.val;
        }
        int left = postOrder(node.left, node);
        int right = postOrder(node.right, node);
        return left + right;
    }
}

解法三:层序遍历(左、右叶子节点都不需要加入到队列中)

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null)
            return 0;
        int sum = 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
			TreeNode node = queue.poll();
            if (node.left != null) {
            	//如果是左叶子节点,则将其值累加到结果集中,不需要加入到队列中
                if (isLeafNode(node.left)) {
                    sum += node.left.val;
                } else {
                	//否则加入到队列中
                    queue.offer(node.left);
                }
            }
            //如果右节点不为空并且不是右叶子节点则将其加入到队列中
            if (node.right != null && !isLeafNode(node.right))
                queue.offer(node.right);
        }
        return sum;
    }
	//判断该节点是否是叶子节点
    private boolean isLeafNode(TreeNode node){
        return node.left == null && node.right == null;
    }
}

11. leetcode103 二叉树的锯齿形层序遍历

解法一:层序遍历(奇数层尾插记录值,偶数层头插记录值)

class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null)
            return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        //标记层数
        int level = 1;
        while(!queue.isEmpty()){
            int size = queue.size();
            //如果是奇数层,则为从左到右;否则从右到左
            boolean leftToRight = level % 2 == 1;
            LinkedList<Integer> levelNodes = new LinkedList<>();
            for(int i = 0; i < size; i++){
                TreeNode node = queue.poll();
                if(leftToRight){
                	//从左到右,尾插
                    levelNodes.addLast(node.val);
                }else{
                	//从右到左,头插
                    levelNodes.addFirst(node.val);
                }
                if(node.left != null)
                    queue.offer(node.left);
                if(node.right != null)
                    queue.offer(node.right);
            }
            res.add(levelNodes);
            level++;
        }
        return res;
    }
}

解法一优化:层序遍历(使用静态数组存储每一层的值,使用一个boolean值来代替层数计算其从左往右还是从右往左)

class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null)
            return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        //int level = 1;
        boolean leftToRight = true;
        while(!queue.isEmpty()){
            int size = queue.size();
            //boolean leftToRight = level % 2 == 1;
            //LinkedList<Integer> levelNodes = new LinkedList<>();
            Integer[] levelNodes = new Integer[size];
            for(int i = 0; i < size; i++){
                TreeNode node = queue.poll();
                if(leftToRight){
                    //levelNodes.addLast(node.val);
                    levelNodes[i] = node.val;
                }else{
                    //levelNodes.addFirst(node.val);
                    levelNodes[size - 1 - i] = node.val;
                }
                if(node.left != null)
                    queue.offer(node.left);
                if(node.right != null)
                    queue.offer(node.right);
            }
            res.add(Arrays.asList(levelNodes));
            leftToRight = !leftToRight;
        }
        return res;
    }
}

12. leetcode515 在每个树行中找最大值

解法一:层序遍历

class Solution {
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null)
            return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            //记录每一层的最大值
            int MaxValue = Integer.MIN_VALUE;
            for(int i = 0;i < size; i++){
                TreeNode node = queue.poll();
                //将每一层的值进行对比取其最大值
                MaxValue = Math.max(MaxValue, node.val);
                if(node.left != null)
                    queue.offer(node.left);
                if(node.right != null)
                    queue.offer(node.right);
            }
            //将该层的最大值加入结果集中
            res.add(MaxValue);
        }
        return res;
    }
}

解法二:递归实现

class Solution {
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        preOrder(root, 0, res);
        return res;
    }

    private void preOrder(TreeNode node, int curLevel, List<Integer> res){
        if(node == null)
            return;
        if(res.size() == curLevel){
        	//当前层第一个节点,加入到结果集中
            res.add(node.val);
        }else{
        	//每次将结果集中的值与当前节点的值作比较,取较大值
            int maxValue = Math.max(res.get(curLevel), node.val);
            //修改结果集中的最大值
            res.set(curLevel, maxValue);
        }
        preOrder(node.left, curLevel + 1, res);
        preOrder(node.right, curLevel + 1, res);
    }
}

13. leetcode199 二叉树的右视图

解法一:层序遍历(找到每一层的最后一个节点并将其加入结果集中)

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null)
            return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i = 0; i < size; i++){
                TreeNode node = queue.poll();
                //该层的最后一个节点即为右视图所看到的节点
                if(i == size - 1){
                    res.add(node.val);
                }
                if(node.left != null)
                    queue.offer(node.left);
                if(node.right != null)
                    queue.offer(node.right);
            }
        }
        return res;
    }
}

解法二:递归实现(仿照前序遍历,但先遍历右,再遍历左,因此每一层第一个访问的节点即为右视图所看到的节点)

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        dfs(root, 0, res);
        return res;
    }
    private void dfs(TreeNode node, int curLevel, List<Integer> res){
        if(node == null)
            return;
        //每一层第一个访问到的节点即为右视图所看到的节点
        if(res.size() == curLevel){
            res.add(node.val);
        }
        dfs(node.right, curLevel + 1, res);
        dfs(node.left, curLevel + 1, res);
    }
}

14. leetcode100 相同的树

解法一:递归实现

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
    	//如果p为空并且q为空,则是相同的树
        if(p == null && q == null)
            return true;
        //如果p为空q不为空 or p不为空q为空,则不是相同的树
        if(p == null || q == null)
            return false;
        //如果p和q的值不相等,则不是相同的树
        if(p.val != q.val)
            return false;
        //递归判断其左子树和右子树,只有左右子树都相同时才是相同的树
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
}

解法二:层序遍历

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p == null && q == null)
            return true;
        if(p == null || q == null)
            return false;
        Queue<TreeNode> queue1 = new LinkedList<>();
        Queue<TreeNode> queue2 = new LinkedList<>();
        queue1.offer(p);
        queue2.offer(q);
        while(!queue1.isEmpty() && !queue2.isEmpty()){
            TreeNode node1 = queue1.poll();
            TreeNode node2 = queue2.poll();
            //如果node1的值不等于node2的值,直接返回false
            if(node1.val != node2.val)
                return false;
            TreeNode left1 = node1.left;
            TreeNode right1 = node1.right;
            TreeNode left2 = node2.left;
            TreeNode right2 = node2.right;
            //异或:相同返回false,不同返回true
            //如果left1为空left2不为空 or left1不为空left2为空,则直接返回false
            if(left1 == null ^ left2 == null)
                return false;
            //如果right1为空right2不为空 or right1不为空right2为空,则直接返回false
            if(right1 == null ^ right2 == null)
                return false;
            if(left1 != null) queue1.offer(left1);
            if(right1 != null) queue1.offer(right1);
            if(left2 != null) queue2.offer(left2);
            if(right2 != null) queue2.offer(right2);
        }
        //只有两个队列都为空时,才是相同的树
        return queue1.isEmpty() && queue2.isEmpty();
    }
}

15. leetcode101 对称二叉树

解法一:递归实现

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null)
            return true;
        return isMirror(root.left, root.right);
    }
	//判断两棵树是否是镜像
    private boolean isMirror(TreeNode t1, TreeNode t2){
        if(t1 == null && t2 == null)
            return true;
        if(t1 == null || t2 == null)
            return false;
        if(t1.val != t2.val)
            return false;
        return isMirror(t1.left, t2.right) && isMirror(t1.right, t2.left);
    }
}

解法二:层序遍历

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null || root.left == null && root.right == null)
            return true;
        Queue<TreeNode> queue = new LinkedList<>();
        //将根节点的左节点入队
        queue.offer(root.left);
        //将根节点的右节点入队
        queue.offer(root.right);
        while(!queue.isEmpty()){
            TreeNode left = queue.poll();
            TreeNode right = queue.poll();
            //如果都为空则跳出当前循环
            if(left == null && right == null)
                continue;
            //如果有一个为空,则返回false
            if(left == null || right == null)
                return false;
            //如果两个节点值不相同,则返回false
            if(left.val != right.val)
                return false;
            queue.offer(left.left);
            queue.offer(right.right);

            queue.offer(left.right);
            queue.offer(right.left);
        }
        return queue.isEmpty();
    }
}

16. leetcode662 二叉树最大宽度

解法一:BFS层序遍历,给每一层节点标记序号

class Solution {
    class Node{
        int treeNodeNum;
        TreeNode treeNode;

        public Node(TreeNode treeNode, int treeNodeNum){
            this.treeNode = treeNode;
            this.treeNodeNum = treeNodeNum;
        }
    }
    
    public int widthOfBinaryTree(TreeNode root) {
        if(root == null)
            return 0;
        Queue<Node> queue = new LinkedList<>();
        queue.offer(new Node(root, 1));
        int maxWidth = 0;
        while(!queue.isEmpty()){
            int size = queue.size();
            int startNum = 0;
            int endNum = 0;
            for(int i = 0; i < size; i++){
                Node curNode = queue.poll();
                TreeNode treeNode = curNode.treeNode;
                int treeNodeNum = curNode.treeNodeNum;
                //i == 0表示该层第一个节点,即该层最左非空节点
                if(i == 0){
                    startNum = treeNodeNum;
                }
                //i == size - 1表示该层最后一个节点,即该层最右非空节点
                if(i == size - 1){
                    endNum = treeNodeNum;
                }
                if(treeNode.left != null){
                    queue.offer(new Node(treeNode.left, treeNodeNum * 2));
                }
                if(treeNode.right != null){
                    queue.offer(new Node(treeNode.right, treeNodeNum * 2 + 1));
                }
            }
            maxWidth = Math.max(maxWidth, endNum - startNum + 1);
        }
        return maxWidth;
    }
}

解法二:dfs前序遍历初始化该层节点start + end编号,后序遍历向上返回最大宽带

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        return dfs(root, 0, 1, new ArrayList(), new ArrayList());
    }

    private int dfs(TreeNode root, int level, int treeNodeNum, List<Integer> start, List<Integer> end){
        if(root == null)
            return 0;
        //前序
        if(start.size() == level){ //该层第一个节点
            start.add(treeNodeNum);
            end.add(treeNodeNum);
        }else{
            end.set(level, treeNodeNum);
        }
        int leftMaxWidth = dfs(root.left, level + 1, 2 * treeNodeNum, start, end);
        int rightMaxWidth = dfs(root.right, level + 1, 2 * treeNodeNum + 1, start, end);
        //后序
        int curWidth = end.get(level) - start.get(level) + 1;
        return Math.max(curWidth, Math.max(leftMaxWidth, rightMaxWidth));
    }
}

17. leetcode222. 完全二叉树的节点个数

解法一:dfs后序遍历,时间复杂度为O(n)

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

解法二:二分查找 + 位运算,时间复杂度为O(log²n)

规定根节点位于第0层,完全二叉树的最大层数为 h。根据完全二叉树的特性可知,完全二叉树的最左边的节点一定位于最底层,因此从根节点出发,每次访问左子节点,直到遇到叶子节点,该叶子节点即为完全二叉树的最左边的节点,经过的路径长度即为最大层数 h

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int countNodes(TreeNode root) {
        if(root == null)
            return 0;
        //1. 计算完全二叉树的层数
        // 层数是从0开始,根节点为第0层
        int level = 0;
        TreeNode node = root;
        while(node.left != null){
            level++;
            node = node.left;
        }
        //2. 二分查找
        // 完全二叉树的节点数的范围:[2 ^ level, 2 ^ (level + 1) - 1]
        int low = 1 << level;
        int high = (1 << (level + 1)) - 1;
        while(low < high){
            //需要+1
            int mid = low + (high - low + 1) / 2;
            if(exists(root, level, mid)){
                low = mid;
            }else{
                high = mid - 1;
            }
        }
        return low;
    }
    private boolean exists(TreeNode root, int level, int mid){
    	//mask为倒数第二层第一个节点的值,如上图01000
        int mask = 1 << (level - 1);
        TreeNode node = root;
        while(node != null && mask > 0){
        	//例如:mask为01000,mid为10010
        	//mask & mid == 00000,因此向左查找
            if((mask & mid) == 0){
                node = node.left;
            }else{
            	//例如:mask为01000,mid为11000
            	//mask & mid == 01000,因此向右查找
                node = node.right;
            }
            //例如:mask为01000,检查根节点到第二层节点
            // mask >>= 1 后 mask = 00100,检查第二层节点到第三层节点
            mask >>= 1;
        }
        return node != null;
    }
}

18. leetcode114. 二叉树展开为链表

解法一:先前序遍历再串联链表

class Solution {
    public void flatten(TreeNode root) {
        List<TreeNode> list = new ArrayList<>();
        preOrder(root, list);
        for(int i = 1; i < list.size(); i++){
            TreeNode prev = list.get(i - 1);
            TreeNode curr = list.get(i);
            prev.left = null;
            prev.right = curr;
        }
    }

    private void preOrder(TreeNode root, List<TreeNode> list){
        if(root == null)
            return;
        list.add(root);
        preOrder(root.left, list);
        preOrder(root.right, list);
    }
}

解法二:边遍历边串联(前序遍历非递归实现)

class Solution {
    public void flatten(TreeNode root) {
        if(root == null)
            return;
        Deque<TreeNode> stack = new ArrayDeque<>();
        stack.push(root);
        //指向前一个节点
        TreeNode prev = null;
        while(!stack.isEmpty()){
        	//指向当前节点
            TreeNode curr = stack.pop();
            if(prev != null){
                prev.left = null;
                prev.right = curr;
            }
            if(curr.right != null){
                stack.push(curr.right);
            }
            if(curr.left != null){
                stack.push(curr.left);
            }
            prev = curr;
        }
    }
}

解法三:原地改变指针

class Solution {
    public void flatten(TreeNode root) {
        if(root == null)
            return;
        TreeNode curr = root;
        while(curr != null){
        	//如果当前节点的左子树不为空,则去左子树中查找右子树的前继届点
            if(curr.left != null){
            	//记录当前左子树节点
                TreeNode left = curr.left;
                //pre用来标识当前节点左子树中的最右节点
                TreeNode pre = left;
                //寻找左子树的最右节点,也就是根节点右子树的前节点
                while(pre.right != null){
                    pre = pre.right;
                }
                pre.right = curr.right;
                curr.left = null;
                curr.right = left;
            }
            curr = curr.right;
        }
    }
}

19. leetcode236 二叉树的最近公共祖先

解法一:维护节点和父亲节点的关系

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //1. 维护子节点与其对应父节点的关系
        Map<Integer, TreeNode> parent = new HashMap<>();
        dfs(root, parent);

        //2. 从p节点开始依次访问其祖先
        Set<Integer> visited = new HashSet<>();
        while(p != null){
            visited.add(p.val);
            p = parent.get(p.val);
        }

        //3. 从节点q开始,依次访问其祖先
        // 如果第一次遇到了p的祖先,那就是最近公共祖先
        while(q != null){
            if(visited.contains(q.val)){
                return q;
            }
            q = parent.get(q.val);
        }
        return null;
    }
    
    private void dfs(TreeNode node, Map<Integer, TreeNode> parent){
        if(node == null)
            return;
        if(node.left != null)
            parent.put(node.left.val, node);
        if(node.right != null)
            parent.put(node.right.val, node);
        dfs(node.left, parent);
        dfs(node.right, parent);
    }
}

解法二:dfs后序遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || 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 null;
        if(left == null)
            return right;
        if(right == null)
            return left;
        return root;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值