代码随想录算法训练营第三期day15-二叉树02

目录

一.二叉树的层序遍历

1.T102:二叉树的层序遍历

法1、使用队列

法2、递归

2.T107:二叉树的层序遍历Ⅱ

3.T199:二叉树的右视图

4.T637:二叉树的层平均值

5.T429:N叉树的层序遍历

6.T515:在每个树行中找最大值

7.T116:填充每个节点的下一个右侧节点指针

8.T117:填充每个节点的下一个右侧节点指针Ⅱ

9.T104:二叉树的最大深度

10.T111:二叉树的最小深度

二.T226:翻转二叉树

代码实现

法1、递归(深度优先遍历)

法2、迭代(深度优先遍历)

法3、统一迭代(深度优先遍历)

法4、广度优先遍历【迭代】

法5、广度优先遍历【递归】

思考

三.T101:对称二叉树

代码实现

法1、递归

法2、层序(队列)

法3、层序(栈)


一.二叉树的层序遍历

1.T102:二叉树的层序遍历

T: 给你二叉树的根节点 root,返回其节点值的 层序遍历 (即逐层地,从左到右访问所有节点)

提示:

  • 树中节点数目在范围 [0, 2000] 内

  • -1000 <= Node.val <= 1000

S:

法1、使用队列

C++:

   vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if (root == nullptr) return res;
        queue<TreeNode*> que;
        // que.add(root);
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;//每轮都是一个新的vector
            for (int i = 0; i < size; ++i) {
                TreeNode* cur = que.front();
                que.pop();
                vec.push_back(cur->val);
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
            }
            res.push_back(vec);
        }
        return res;
    }

Java:

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> quque = new LinkedList<>();
        quque.add(root);
        while (!quque.isEmpty()) {
            int size = quque.size();
            List<Integer> level = new LinkedList<>();
            for (int i = 0; i < size; ++i) {
                TreeNode cur = quque.poll();
                level.add(cur.val);
                if (cur.left != null) quque.offer(cur.left);
                if (cur.right != null) quque.offer(cur.right);
            }
            res.add(level);
        }
        return res;
    }

法2、递归

C++:

public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        int depth = 0;
        order(root, res, depth);
        return res;
    }
private:
    // void order(TreeNode* node, vector<vector<int>> result, int depth) {//犯错
    void order(TreeNode* node, vector<vector<int>>& result, int depth) {
        if (!node) return;
        if (depth == result.size()) result.push_back(vector<int>());//!=说明前面已经处理过同层节点
        result[depth].push_back(node->val);//肯定是当前层
        order(node->left, result, depth + 1);
        order(node->right, result, depth + 1);
    }

Java:

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        int depth = 0;
        order(root, res, depth);
        return res;
    }
    private void order(TreeNode node, List<List<Integer>> result, int depth) {
        if (node == null) return;
        // if (depth == result.size()) result.add(new LinkedList<>());//都可以
        if (depth == result.size()) result.add(new LinkedList<Integer>());
        result.get(depth).add(node.val);
        order(node.left, result, depth + 1);
        order(node.right, result, depth + 1);
    }

2.T107:二叉树的层序遍历Ⅱ

T:给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

S:

C++:直接在上一题的基础上进行一维子数组的反转就行了

    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> res;
        if (!root) return res;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            TreeNode* node = nullptr;
            for (int i = 0; i < size; ++i) {
                node = que.front();
                que.pop();
                vec.push_back(node->val);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            res.push_back(vec);
        }
        reverse(res.begin(), res.end());//加上这一行就行
        return res;
    }

Java:反转可以自己实现,也可以直接套用工具类的方法

    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Deque<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> list = new LinkedList<>();
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.poll();
                list.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            res.add(list);
        }
        // Collections.reverse(res);
        // return res;
        //自己实现反转(new了一个新的List)
        List<List<Integer>> result = new ArrayList<>();
        for (int i = res.size() - 1; i >= 0; --i) {
            result.add(res.get(i));
        }
        return result;
    }

3.T199:二叉树的右视图

T: 给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

提示:

  • 二叉树的节点个数的范围是 [0,100]

  • -100 <= Node.val <= 100 

S:

层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就行了

C++:self:自己按照前几题的思路写的,但实际上本题不需要额外再用一个临时vector变量

    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if (root != nullptr) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            // vector<int> vec;//self
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                // vec.push_back(node->val);//self
                if (i == (size - 1)) res.push_back(node->val);//Carl
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            // res.push_back(vec[vec.size() - 1]);//self
        }
        return res;
    }

Java:

    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> queue = new ArrayDeque<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                if (i == size - 1) res.add(node.val);
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
            }
        }
        return res;
    }

4.T637:二叉树的层平均值

T: 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

提示:

  • 树中节点数量在 [1, 104] 范围内

  • -231 <= Node.val <= 231 - 1

S:题目已经明示了要用double,那没什么好说的了

C++:

    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> res;
        if (!root) return res;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            double sum = 0;
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                sum += node->val;
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
            res.push_back(sum / size);
        }
        return res;
    }

Java:

    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            double sum = 0;
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                sum += node.val;
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
            }
            res.add(sum / size);
        }
        return res;
    }

5.T429:N叉树的层序遍历

T: 给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
提示:
  • 树的高度不会超过 1000
  • 树的节点总数在 [0, 10^4] 之间
S:和前面唯一的区别就在于每个节点的子节点数不再仅限于2个或以下,其他地方一切照旧
C++:如下注释的三行均编译错误,原因:看看Node的类定义中,children并非指针类型,自然不能和nullptr比较
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> res;
        if (!root) return res;
        queue<Node*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            for (int i = 0; i < size; ++i) {
                Node* node = que.front();
                que.pop();
                vec.push_back(node->val);
                // if (!node->children || node->children.size() == 0) continue;
                // if (node->children == nullptr || node->children.size() == 0) continue;//invalid operands to binary expression
                // if (node->children == NULL || node->children.size() == 0) continue;//comparison between NULL and non-pointer
                if (node->children.size() == 0) continue;
                for (int j = 0; j < node->children.size(); ++j) {
                    if (node->children[j]) {
                        que.push(node->children[j]);
                    }
                }
            }
            res.push_back(vec);
        }
        return res;
    }

Java:

    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> res = new LinkedList<>();
        if (root == null) return res;
        Deque<Node> queue = new LinkedList<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> list = new LinkedList<>();
            for (int i = 0; i < size; ++i) {
                Node node = queue.pollFirst();
                list.add(node.val);
                if (node.children != null && node.children.size() >= 0) {//设置反向然后continue也行
                    for (Node child : node.children) {
                        queue.addLast(child);
                    }
                }
            }
            res.add(list);
        }
        return res;
    }

6.T515:在每个树行中找最大值

T515: 给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

提示:

  • 二叉树的节点个数的范围是 [0,104]

  • -231 <= Node.val <= 231 - 1

S:找出最大值的方法有很多,可以自己实现,也可以借助各种语言自带的工具类方法

C++:

    vector<int> largestValues(TreeNode* root) {
        vector<int> res;
        if (!root) return res;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            int maxVal = INT_MIN;//
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                maxVal = node->val > maxVal ? node->val : maxVal;//
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            res.push_back(maxVal);
        }
        return res;
    }

Java:

    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        if (root == null) return res;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            // List<Integert> candidates = new ArrayList<>();
            int maxVal = Integer.MIN_VALUE;
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                // candidates.add(node.val);
                maxVal = Math.max(maxVal, node.val);
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
            }
            // res.add(Math.max(candidates))//without this usage
            res.add(maxVal);
        }
        return res;
    }

7.T116:填充每个节点的下一个右侧节点指针

T116:给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {

  int val;

  Node *left;

  Node *right;

  Node *next;

}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

提示:

  • 树中节点的数量在 [0, 212 - 1] 范围内

  • -1000 <= node.val <= 1000

进阶:

  • 你只能使用常量级额外空间。

  • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

S:

C++:
    Node* connect(Node* root) {
        queue<Node*> que;
        if (root) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            Node* preNode;
            Node* curNode;
            for (int i = 0; i < size; ++i) {
                if (i == 0) {
                    preNode = que.front();// 取出一层的头结点
                    que.pop();
                    curNode = preNode;
                } else {
                    curNode = que.front();
                    que.pop();
                    preNode->next = curNode;// 本层前一个节点的next指向本节点
                    // preNode = preNode->next;//
                    preNode = curNode;//和上一行哪种都可以
                }
                if (curNode->left) que.push(curNode->left);
                if (curNode->right) que.push(curNode->right);
            }
            preNode->next = nullptr;//本层最后一个节点指向空
        }
        return root;
    }

Java:

    public Node connect(Node root) {
        Deque<Node> queue = new LinkedList<>();
        if (root != null) queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            Node preNode = null;
            Node curNode = null;
            for (int i = 0; i < size; ++i) {
                if (i == 0) {
                    preNode = queue.pollFirst();
                    curNode = preNode;
                } else {
                    curNode = queue.pollFirst();
                    preNode.next = curNode;
                    preNode = curNode;
                }
                if (curNode.left != null) queue.addLast(curNode.left);
                if (curNode.right != null) queue.addLast(curNode.right);
            }
            preNode.next = null;
        }
        return root;
    }

8.T117:填充每个节点的下一个右侧节点指针Ⅱ

T117:给定一个二叉树

struct Node {

  int val;

  Node *left;

  Node *right;

  Node *next;

}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

进阶:

  • 你只能使用常量级额外空间。

  • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

提示:

  • 树中的节点数小于 6000
  • -100 <= node.val <= 100

S:和上一题的差别只是在于此题不是完美二叉树,思路和代码完全一样(略)

9.T104:二叉树的最大深度

T104:给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

S:一样的套路,每迭代一层就层数+1,最后得出的结果就是最大层数,也就是二叉树的最大深度

C++:

    int maxDepth(TreeNode* root) {
        // if (!root) return -1;
        if (!root) return 0;
        queue<TreeNode*> que;
        que.push(root);
        int maxDepth = 0;
        while (!que.empty()) {
            int size = que.size();
            ++maxDepth;
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                // ++maxDepth;
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return maxDepth;
    }

Java:

    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        int maxDepth = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            ++maxDepth;
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
            }
        }
        return maxDepth;
    }

10.T111:二叉树的最小深度

T111: 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
提示:
  • 树中节点数的范围在 [0, 105] 内
  • -1000 <= Node.val <= 1000
S:

本题依旧可以使用层序遍历的方式来解决,思路是一样的。

需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点,而且一定是第一次(层)遇到的时候是。

    int minDepth(TreeNode* root) {
        if (!root) return 0;
        // int minDepth = INT_MAX;
        int depth = 0;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            ++depth;
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
                if (!node->left && !node->right) {// 当左右孩子都为空的时候,说明是最低点的一层了,退出
                    // minDepth = depth;
                    // break;
                    return depth;//只要第一次(层)遇到,就绝对是最小深度
                    // minDepth = depth;
                    // return minDepth;
                }
            }
            // minDepth = depth < minDepth ? depth : minDepth;//完全不需要
        }
        // return minDepth;
        return depth;//如果刚好是满二叉树,那就返回最后的层数即可
    }

Java:

    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        int depth = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            ++depth;
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
                if (node.left == null && node.right == null) return depth;
            }
        }
        return depth;
    }

二.T226:翻转二叉树

T226: 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

提示:

  • 树中节点数目范围在 [0, 100] 内

  • -100 <= Node.val <= 100

S:在遍历的基础上,加上当前节点的左右子节点交换即可

代码实现

法1、递归(深度优先遍历)

C++:

//【前序】
public:
    TreeNode* invertTree(TreeNode* root) {
        // if (!root) return root;
        preOrderTraversal(root);
        return root;
    }
private:
    void preOrderTraversal(TreeNode* node) {
        if (!node) return;
        swap(node->left, node->right);//可以空空交换
        preOrderTraversal(node->left);
        preOrderTraversal(node->right);
    }

//【(伪)中序】
public:
    TreeNode* invertTree(TreeNode* root) {
        // if (!root) return root;
        inOrderTraversal(root);
        return root;
    }
private:
    void inOrderTraversal(TreeNode* node) {
        if (!node) return;
        inOrderTraversal(node->left);
        swap(node->left, node->right);
        inOrderTraversal(node->left);//注意此处,已经不是原来的中序遍历递归了
    }

//后序略

Java:与C++的代码也没什么区别,就以上面略的后序为例

    public TreeNode invertTree(TreeNode root) {
        postOrder(root);
        return root;
    }
    private void postOrder(TreeNode node) {
        if (node == null) return;
        postOrder(node.left);
        postOrder(node.right);
        swapChild(node);
        // swapNode(node.left, node.right);//无效(原因见思考part)
    }
    private void swapChild(TreeNode node) {
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }
    private void swapNode(TreeNode node1, TreeNode node2) {
        TreeNode temp = node1;
        node1 = node2;
        node2 = temp;
    }

法2、迭代(深度优先遍历)

C++:

//【前序】
    TreeNode* invertTree(TreeNode* root) {
        // if (!root) return root;//either
        stack<TreeNode*> st;
        if (root) st.push(root);//or
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            swap(node->left, node->right);
            if (node->right) st.push(node->right);
            if (node->left) st.push(node->left);
        }
        return root;
    }

法3、统一迭代(深度优先遍历)

C++:

//【前序】
    TreeNode* invertTree(TreeNode* root) {
        if (!root) return root;
        stack<TreeNode*> st;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node) {
                st.pop();
                if (node->right) st.push(node->right);
                if (node->left) st.push(node->left);
                st.push(node);
                st.push(nullptr);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                swap(node->left, node->right);
            }
        }
        return root;
    }
//【中序】
    TreeNode* invertTree(TreeNode* root) {
        if (!root) return root;
        stack<TreeNode*> st;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node) {
                st.pop();
                if (node->right) st.push(node->right);
                st.push(node);
                st.push(nullptr);
                if (node->left) st.push(node->left);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                swap(node->left, node->right);
            }
        }
        return root;
    }

Java:

//【后序】
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return root;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.offerFirst(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.getFirst();
            if (node != null) {
                queue.removeFirst();
                queue.addFirst(node);
                queue.addFirst(null);
                if (node.right != null) queue.push(node.right);
                if (node.left != null) queue.push(node.left);
            } else {
                queue.pollFirst();
                node = queue.peekFirst();
                queue.pop();
                swapChild(node);
            }
        }
        return root;
    }
    private void swapChild(TreeNode node) {
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }

法4、广度优先遍历【迭代】

C++:

    TreeNode* invertTree(TreeNode* root) {
        if (!root) return root;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                TreeNode* node = que.front();
                que.pop();
                swap(node->left, node->right);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return root;
    }

Java:

    public TreeNode invertTree(TreeNode root) {
        if (root == null) return root;
        Deque<TreeNode> queue = new LinkedList<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                TreeNode node = queue.pollFirst();
                // swapNode(node.left, node.right);//无效(搞清楚原因!!!)
                swapChild(node);
                if (node.left != null) queue.addLast(node.left);
                if (node.right != null) queue.addLast(node.right);
            }
        }
        return root;
    }
    private void swapChild(TreeNode node) {
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }

法5、广度优先遍历【递归】

这个方法可以用是可以用,但毕竟不是真的在遍历,所以vector的存在可能有点多余

C++:

    TreeNode* invertTree(TreeNode* root) {
        if (!root) return root;
        vector<vector<int>> vec;
        int depth = 0;
        orderByLevel(root, vec, depth);
        return root;
    }
    void orderByLevel(TreeNode* node, vector<vector<int>>& vec, int depth) {
        if (!node) return;
        if (depth == vec.size()) vec.push_back(vector<int>());
        vec[depth].push_back(node->val);
        swap(node->left, node->right);
        orderByLevel(node->left, vec, depth + 1);
        orderByLevel(node->right, vec, depth + 1);
    }

思考

Q:写的时候发现一个问题,那就是交换左右子节点必须传入节点本体,传入左右子节点则无法交换?(见递归遍历写法中Java部分)

A:思考之后得出结论:如果传入左右子节点,那么交换的只是左右子节点指针的指向,而对它们的父节点来说,其左右子节点(的内存空间)并没有交换

三.T101:对称二叉树

T101:给你一个二叉树的根节点 root , 检查它是否轴对称。

提示:

  • 树中节点数目在范围 [1, 1000] 内

  • -100 <= Node.val <= 100

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

S:本题无论是递归还是迭代,关键在于一定要把空值(子节点)与对称的所有情况考虑周全!

代码实现

法1、递归

C++:

    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        return compare(root->left, root->right);
    }
    bool compare(TreeNode* left, TreeNode* right) {
        if (!left && right) return false;
        else if (left && !right) return false;
        else if (!left && !right) return true;
        else if (left->val != right->val) return false;
        else {
            return compare(left->left, right->right) && compare(left->right, right->left);
        }
    }

Java:

    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return compare(root.left, root.right);
    }
    private boolean compare(TreeNode left, TreeNode right) {
        if (left == null && right == null) return true;
        else if (left != null && right == null) return false;
        else if (left == null && right != null) return false;
        else if (left.val != right.val) return false;
        else {
            return compare(left.left, right.right) && compare(left.right, right.left);
        }
    }

法2、层序(队列)

C++:

    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        queue<TreeNode*> que;
        que.push(root->left);
        que.push(root->right);
        while (!que.empty()) {
            TreeNode* left = que.front();
            que.pop();
            TreeNode* right = que.front();
            que.pop();
            if (!left && !right) {
                // return true;//别傻!
                continue;
            }

            // 左右一个节点不为空,或者都不为空但数值不相同,返回false
            if (!left || !right || left->val != right->val) {
                return false;
            }
            que.push(left->left);
            que.push(right->right);
            que.push(left->right);
            que.push(right->left);
        }
        return true;
    }

Java:

    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        Deque<TreeNode> que = new LinkedList<>();
        que.offerLast(root.left);
        que.addLast(root.right);
        while (!que.isEmpty()) {
            TreeNode left = que.pop();
            TreeNode right = que.pollFirst();
            if (left == null && right == null) {
                continue;
            }
            if (left == null || right == null || left.val != right.val) {
                return false;
            }
            que.addLast(left.left);
            que.addLast(right.right);
            que.addLast(left.right);
            que.addLast(right.left);
        }
        return true;
    }

法3、层序(栈)

跟队列几乎一模一样

C++:

    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        stack<TreeNode*> st;
        st.push(root->right);
        st.push(root->left);
        while (!st.empty()) {
            TreeNode* left = st.top();
            st.pop();
            TreeNode* right = st.top();
            st.pop();
            if (!left && !right) continue;
            if (!left || !right || left->val != right->val) {
                return false;
            }
            st.push(left->left);
            st.push(right->right);
            st.push(left->right);
            st.push(right->left);
        }
        return true;
    }

Java:

    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root.right);
        stack.push(root.left);
        while (!stack.isEmpty()) {
            TreeNode left = stack.pop();
            TreeNode right = stack.pop();
            if (left == null && right == null) continue;
            if (left == null || right == null || left.val != right.val) 
                return false;
            stack.push(right.right);
            stack.push(left.left);
            stack.push(right.left);
            stack.push(left.right);
        }
        return true;
    }

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值