【问题标题】:N-ary Tree Level Traversal bug (C++)N-ary Tree Level Traversal bug (C++)
【发布时间】:2020-01-05 14:27:04
【问题描述】:

我正在对 LeetCode 进行编码挑战,我被要求遍历每个级别,最后返回一个嵌套向量,其中包含每个值的节点值。

如果我有一棵像这样的树:

这是

输入:root = [1,null,3,2,4,null,5,6]

预期的输出是

输出:[[1],[3,2,4],[5,6]]

Node的定义如下:

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

我正在尝试如下迭代解决方案:

class Solution {
public:
    vector<vector<int>> answer;
    stack<Node*> nodes;
    vector<vector<int>> levelOrder(Node* root) {
        if(root == NULL)
            return answer;
        nodes.push(root);
        answer.push_back(vector<int>() = {root->val});
        while(!nodes.empty())
        {
            Node* curr = nodes.top();
            nodes.pop();
            vector<int>temp;

            for(int i = 0; i < curr->children.size(); i++)
            {
                nodes.push(curr->children[i]);
                temp.push_back(curr->children[i]->val);
            }
            if(temp.size() != 0)
                answer.push_back(temp);
        }
        return answer;
    }
};

但它始终未能通过输入为的第 20 个测试用例:

[1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]

期望是:

[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]

我的输出是

[[1],[2,3,4,5],[9,10],[13],[8],[12],[6,7],[11],[14]]

我无法在纸上可视化和绘制这个 N 叉树,所以我很难理解我的算法哪里出错了。

【问题讨论】:

  • 如果您仔细查看上面引用的示例输入和输出,您会发现根本不需要构建任何树。输出与输入中的数据系列相同,只是用[] 分组,而不是用,null 分隔。但是,您必须计算属于每个级别的运行。例如,如果节点 4 有一个子节点 8,则输入将类似于 `[1,null,3,2,4,null,5,6,null,null,8]` 并且预期的输出将是 `[[ 1],[3,2,4],[5,6,8]]` - 注意树的第三行中三个运行(一个空)的串联。

标签: c++ tree traversal


【解决方案1】:

您的代码的问题在于,对于您访问的每个节点,您都将其所有子节点作为新列表附加到答案列表中。您的代码不会像解决方案所期望的那样将处于同一级别但具有不同父级的子级分组到一个列表中。

让我们逐步检查您的代码,看看会发生什么:

  • 在循环之前,将根节点压入堆栈,并将具有根节点值的单例集压入答案:

    stack = {1}
    answer = { {1} }
    
  • 第一次迭代从堆栈中弹出 1。然后,您遍历子节点 2、3、4、5,这些子节点被压入堆栈。之后,孩子的列表被推送到答案列表中。

    stack = {2,3,4,5}
    answer = { {1}, {2,3,4,5} }
    
  • 下一次迭代将 5 从堆栈中弹出。然后迭代孩子 9、10。它们被推入堆栈。之后,孩子的列表被推送到答案列表中。

    stack = {2,3,4,9,10}
    answer = { {1}, {2,3,4,5}, {9, 10} }
    
  • 下一次迭代从堆栈中弹出 10。它没有孩子,所以什么也不会发生。

    stack = {2,3,4,9}
    answer = { {1}, {2,3,4,5}, {9, 10} }
    
  • 下一次迭代将 9 从堆栈中弹出。然后迭代单个子 13,它被推入堆栈。将包含 13 的单例列表推送到答案集。

    stack = {2,3,4}
    answer = { {1}, {2,3,4,5}, {9, 10}, {13} }
    
  • 下一次迭代将 4 从堆栈中弹出。然后迭代单个子 8,将其推入堆栈。将包含 8 的单例列表推送到答案集。

    stack = {2,3,8}
    answer = { {1}, {2,3,4,5}, {9, 10}, {13}, {8} }
    

    您可以从这里看到您的答案列表是错误的。 8 与 9 和 10 处于同一级别,因此应该已将其添加到答案列表的 {9,10} 子列表中,而不是创建新列表 {8}。这应该足以说明问题,所以我不再单步执行代码。

为了确保同一级别的节点在答案列表中被分组到同一个子列表中,我们必须在访问每个节点时跟踪当前级别。我们可以通过扩展堆栈来保存当前节点及其深度的对来做到这一点。然后,深度 d 的每个节点值将附加到答案列表中的 dth 子列表中。这样可以确保同一级别的节点被分组到一个子列表中。

std::vector<std::vector<int>> get_vals_per_level(const Node *root) {

  std::vector<std::vector<int>> vals_per_level{};
  std::stack<std::pair<const Node *, int>> stack{};

  stack.emplace(root, 0);

  while (!stack.empty()) {
    auto [current, depth]{stack.top()};
    stack.pop();

    if (vals_per_level.size() == depth) {
      vals_per_level.emplace_back();
    }

    // Append node value to the answer list for the current depth
    vals_per_level[depth].push_back(current->val);

    auto& children{current->children};

    for (auto it{children.rbegin()}; it != children.rend(); it++) {
      stack.emplace(*it, depth + 1);
    }
  }

  return vals_per_level;
}

代码使用 C++17 中的structured bindings

【讨论】:

    猜你喜欢
    • 2022-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2014-06-02
    • 1970-01-01
    相关资源
    最近更新 更多