LeetCode(7)-树:DFS/BFS类问题

本文总结了树的遍历算法,包括二叉树和N叉树的前序、中序、后序及层次遍历,同时介绍了如何将有序数组转换为二叉搜索树和根据前序与中序遍历序列构造二叉树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此文总结树中和深度优先遍历(DFS)和广度优先遍历(BFS)相关的问题.

1. LeetCode 144. 二叉树的前序遍历

给定一个二叉树,返回它的 前序 遍历。

示例:

输入: [1,null,2,3]
1

2
/
3

输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    //递归版本
    List<Integer> res = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        //递归终止条件
        if(root == null) return res;
        res.add(root.val);
        preorderTraversal(root.left);
        preorderTraversal(root.right);
        return res;
    }
    
    //迭代版本
    public List<Integer> preorderTraversal(TreeNode root) {
        //迭代做法:申请一个stack,现将head压入;当stack不为空时,
        //弹出树节点即为当前遍历所得,并且判断树节点是否存在右子节点,
        //存在则压栈;再判断是否存在左子节点,存在则压栈 
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode pop = stack.pop();
            res.add(pop.val);
            if (pop.right != null) stack.push(pop.right);
            if (pop.left != null) stack.push(pop.left);
        }
        return res;
    }

2. LeetCode 589. N叉树的前序遍历

给定一个 N 叉树,返回其节点值的前序遍历。

例如,给定一个 3叉树 :

在这里插入图片描述

返回其前序遍历: [1,3,5,6,2,4]。

说明: 递归法很简单,你可以使用迭代法完成此题吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 List<Integer> res = new ArrayList<>();
    public List<Integer> preorder(Node root) {
        //递归做法,和二叉树的前序遍历相似,
        //不过需要使用for循环来获取到每个孩子节点
        if (root == null) return res;
        res.add(root.val);
        for (int i = 0; i < root.children.size(); i++) {
            Node node = root.children.get(i);
            preorder(node);
        }
        return res;
    }
    
    public List<Integer> preorder(Node root) {
        //迭代的做法,和二叉树的前序遍历迭代做法相似,
        //也是需要一个栈,不过需要使用for循环来获取到每个孩子节点
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            Node pop = stack.pop();
            res.add(pop.val);
            for (int i = pop.children.size() - 1; i >= 0; i--) {
                //从右侧开始入栈
                stack.push(pop.children.get(i));
            }
        }
        return res;
    }

3. LeetCode 94. 二叉树的中序遍历

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
1

2
/
3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        //递归终止条件
        if (root == null) return res;
        inorderTraversal(root.left);
        res.add(root.val);
        inorderTraversal(root.right);
        return res;
    }


public List<Integer> inorderTraversal(TreeNode root) {
        //迭代做法,思路是创建一个栈,当栈不为空或当前节点不为空时,存在以下判断:
        //当节点不为空,此时将该节点压入栈中,并且将该节点置为其左节点(下移过程)
        //当节点为空时,弹栈出来的节点即为遍历结果,并且将当前节点置为弹栈节点的右子节点(上移过程)
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                //压栈
                stack.push(root);
                //置为左子节点
                root = root.left;
            } else {
                //弹栈
                TreeNode pop = stack.pop();
                res.add(pop.val);
                //将当前节点置为弹栈节点的右子节点
                root = pop.right;
            }
        }
        return res;
    } 

4. LeetCode 145.二叉树的后序遍历

List<Integer> res = new ArrayList<Integer>();
    public List<Integer> postorderTraversal(TreeNode root) {
        //递归过程
        if (root == null) return res; 
        postorderTraversal(root.left);
        postorderTraversal(root.right);
        res.add(root.val);
        return res;
    }
    
    public List<Integer> postorderTraversal(TreeNode root) {
       List<Integer> res = new ArrayList<Integer>();
        if (root == null) return res;
        //stack1用以当中'中转站'
        Stack<TreeNode> stack1 = new Stack<>();
        //stack2用以保存遍历结果
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.push(root);
        while (!stack1.isEmpty()) {
            //弹栈即为遍历结果
            root = stack1.pop();
            stack2.push(root);
            //stack1压入左子节点
            if (root.left !=null) stack1.push(root.left);
            //stack1压入右子节点
            if (root.right !=null) stack1.push(root.right);
        }
        //将stack2的结果取出
        while (!stack2.isEmpty()) {
            res.add(stack2.pop().val);
        }
        return res;
    }

5. LeetCode 590. N叉树的后序遍历

List<Integer> res = new ArrayList<>();
    public List<Integer> postorder(Node root) {
        //递归终止条件
        if (root == null) return res;
        for (int i = 0; i < root.children.size(); i++) {
            postorder(root.children.get(i));
        }
        res.add(root.val);
        return res;
    }
    
    public List<Integer> postorder(Node root) {
        //采用迭代的方法,思路是创建两个栈stack1和stack2,
        //其中stack1作为中转栈,stack2作为保存结果栈,
        //一开始现将root压入stack1中,当stack1不为空时,弹栈并放入stack2中,
        //将弹栈节点由左至右压入stack1中
        //当stack1为空时,将stack2依次弹栈则得遍历结果
       List<Integer> res = new ArrayList<Integer>();
        if (root == null) return res;
        //stack1用以当中'中转站'
        Stack<Node> stack1 = new Stack<>();
        //stack2用以保存遍历结果
        Stack<Node> stack2 = new Stack<>();
        stack1.push(root);
        while (!stack1.isEmpty()) {
            Node pop = stack1.pop();
            stack2.push(pop);
            for (int i = 0; i < pop.children.size(); i++) {
                stack1.push(pop.children.get(i));
            }
        }
        //获取结果
        while (!stack2.isEmpty()) {
            res.add(stack2.pop().val);
        }
        return res;
    }

6. LeetCode 102. 二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

3
/
9 20
/
15 7
返回其层次遍历结果:

[
[3],
[9,20],
[15,7]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

public List<List<Integer>> levelOrder(TreeNode root) {
            if (root == null) return new ArrayList<>();
            ArrayList<List<Integer>> res = new ArrayList<>();
            //FIFO队列
            LinkedList<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()) {
                ArrayList<Integer> levelNodes = new ArrayList<>();
                int len = queue.size();
                //遍历存储这一层的值
                for (int i = 0; i < len; i++) {
                    TreeNode poll = queue.poll();
                    //出队的即为遍历结果
                    levelNodes.add(poll.val);
                    //如果出队的节点含有左子节点则添加进队列
                    if (poll.left != null) queue.offer(poll.left);
                    //如果出队的节点含有右子节点则添加进队列
                    if (poll.right != null) queue.offer(poll.right);
                }
                //添加这一层的结果进res中
                res.add(levelNodes);
            }
            return res;
        }

7. LeetCode 102. N叉树的层序遍历

public List<List<Integer>> levelOrder(Node root) {
        // TODO: 19-7-12 思考过程类似102题二叉树的层次遍历 
        ArrayList<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        LinkedList<Node> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            ArrayList<Integer> levelNodes = new ArrayList<>();
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                //存储层次
                Node poll = queue.poll();
                //出队的即为遍历结果
                levelNodes.add(poll.val);
                List<Node> childrens = poll.children;
                //孩子节点从左至右入队
                for (int j = 0; j < childrens.size(); j++) {
                    queue.offer(childrens.get(j));
                }
            }
            //存储当前层次的结果
            res.add(levelNodes);
        }
        return res;
    }

8. LeetCode 102. N叉树的层序遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

3
/
9 20
/
15 7
返回锯齿形层次遍历如下:

[
[3],
[20,9],
[15,7]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        int depth = 0;
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int len = queue.size();
            ArrayList<Integer> oneRes = new ArrayList<>();
            for (int i = 0; i < len; i++) {
                TreeNode poll = queue.poll();
                //判断是奇数层还是偶数层,奇数层从左往右收集节点值,偶数层则从右往左收集节点值
                if (depth % 2 == 0) {
                    //奇数层
                    oneRes.add(poll.val);
                } else {
                    //偶数层
                    oneRes.add(0, poll.val);
                }
                if (poll.left != null) queue.offer(poll.left);
                if (poll.right != null) queue.offer(poll.right);
            }
            res.add(oneRes);
            depth++;
        }
        return res;
    }

9. LeetCode 108. 将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

0
/
-3 9
/ /
-10 5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    private TreeNode helper(int[] nums, int left, int right) {
        //递归终止条件
        if (left > right) return null;
        //递归过程
        //求出当前中间节点,并且递归地连接左右子树
        int middle = left + (right - left) / 2;
        TreeNode root = new TreeNode(nums[middle]);
        root.left = helper(nums, left, middle - 1);
        root.right = helper(nums, middle + 1, right);
        return root;
    }

10. LeetCode 105. 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

3
/
9 20
/
15 7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

public TreeNode buildTree(int[] preorder, int[] inorder) {
        Map<Integer, Integer> inorder_map = new HashMap<>();
        int n = inorder.length;
        for (int i = 0; i < n; i++) inorder_map.put(inorder[i], i);

        return helper(preorder, 0, n, inorder, 0, n, inorder_map);


    }

    private TreeNode helper(int[] preorder, int pre_start, int pre_end, int[] inorder, int in_start, int in_end, Map<Integer, Integer> inorder_map) {
        if (pre_start == pre_end) return null;
        //从先序遍历中取当前根节点
        TreeNode root = new TreeNode(preorder[pre_start]);
        //从map中取当前根节点对于中序遍历数组的索引位置
        int loc = inorder_map.get(preorder[pre_start]);
        //划分成左右两个子树去构建
         root.left = helper(preorder, pre_start + 1, pre_start + loc - in_start + 1, inorder, in_start, loc - 1, inorder_map);
        root.right = helper(preorder, pre_start + loc - in_start + 1, pre_end, inorder, loc + 1, in_end, inorder_map);
        return root;
    }

还有一种基于Arrays.copyOfRange的写法,这种写法更加地直观和简单:

import java.util.*;
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return rebuild(preorder, inorder); 
    }
    
    private TreeNode rebuild(int[] preorder, int[] inorder) {
        if (preorder.length == 0 || inorder.length == 0) {
            return null;
        }
        //当前根节点
        TreeNode root = new TreeNode(preorder[0]);
        //找到当前根节点位于中序遍历的索引
        int rootIndex = findIndex(inorder, preorder[0]);
        //递归
        root.left = rebuild(Arrays.copyOfRange(preorder, 1, rootIndex + 1),
                            Arrays.copyOfRange(inorder, 0, rootIndex));
        root.right = rebuild(Arrays.copyOfRange(preorder, rootIndex + 1, preorder.length),
                            Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length));
        return root;
    }
    
    private int findIndex(int[] array, int target) {
        for (int i = 0; i < array.length; i++) {
            if (array[i] == target) return i;
        }
        return -1;
    }
}

未完持续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值