【问题标题】:Propagating values from the leaf to the root将值从叶子传播到根
【发布时间】:2018-03-13 00:15:33
【问题描述】:

我已经解决了很多与树相关的问题,但是,我仍然对树的某个特定方面(一般递归)没有信心:

如何将值从叶传播到根?

例如,假设我们有一棵二叉树,其中我们必须找到总和最小的从根到叶的路径。对于树图像here,总和将为7(对应于两个路径0-3-2-1-1 或0-6-1)。

我写了以下代码:

struct Node
{
  int cost;
  vector<Node *> children;
  Node *parent;
};

int getCheapestCost( Node *rootNode )
{
  if(!rootNode) return 0;

  return dfs(rootNode, INT_MAX, 0);
}

int dfs(Node* rootNode, int minVal, int currVal) {
  if(!rootNode) return;

  currVal+=rootNode->cost;
  if(rootNode->children.empty()) {
    minVal = min(minVal, currVal);
    return minVal;
  }

  for(auto& neighbor: rootNode->children) {
    dfs(neighbor, minVal, currVal);
  }

  return currVal;    //this is incorrect, but what should I return?
}

我知道最后一个 return currVal 不正确 - 但是我应该返回什么?从技术上讲,我只想在到达叶节点时返回 minVal 的值(当我在中间节点时没有值)。那么,如何将 minVal 从叶节点传播到最顶层的 root 节点?

P.S.:我正在准备面试,这对我来说是一个很大的痛苦领域,因为我几乎每次都被困在这一点上。我将非常感谢任何帮助。谢谢。

编辑:对于这个特定的,我以某种方式 wrote a solution 使用传递引用。

【问题讨论】:

    标签: c++ tree tree-traversal


    【解决方案1】:

    在您的 for 中保存所有子级的 minVal 并返回 minVal 而不是 currVal。

    for(auto& neighbor: rootNode->children) {
      minVal = min(minVal, dfs(neighbor, minVal, currVal));
    }
    return minVal;
    

    这样你总是返回 minVal,通过递归一直到第一次调用。

    编辑:解释

    我将使用您在问题中提供的tree 作为示例。我们将从在根 (0) 处输入树开始。它会将 0 添加到 currVal,不会输入第一个 if,然后输入 for。一旦它在那里,该函数将从第一个孩子再次调用。

    在第一个节点(5),它会添加那个值,检查它是否结束,然后转到下一个节点(4),再次添加,currVal现在是9。然后,因为(4)没有孩子们,它会返回 min(currVal, minVal)。此时minVal为INT_MAX,所以返回9。

    一旦这个值被返回,我们回到调用它的函数,它位于节点(5),正好在我们调用(4)的时候,我们将(根据我的修改)比较哪个值它以 minVal 返回。

    min(minVal, dfs(neighbor, minVal, currVal))
    

    此时,重要的是要注意当前的 minVal 仍然是 INT_MAX,因为它不是引用,这是传递给函数的值。因此,我们现在将其设置为 9。

    如果 (5) 有其他孩子,我们现在将输入一个新的 dfs 实例,一旦我们得到结果,将该值与 9 进行比较,但既然我们没有,我们结束for循环并返回minVal,返回根节点(0)。

    从那里,相信你可以猜到会发生什么,我们输入node(3),它分支到(2)->(1)->(1)和(0)->(10),返回7和13分别到for循环,节点(6)最终也会返回7到(0)的for循环。

    最后,(0) 将首先将 INT_MAX 与 9 进行比较,然后与 7 进行比较,最后再次与 7 进行比较,将 7 返回给 getCheapestCost

    简而言之:

    您的代码将继续输入 dfs 直到找到没有子节点的节点,一旦发生这种情况,它将返回它从该节点获得的 minVal,并返回调用它的函数,即父节点。

    一旦在父节点中,您需要检查哪些子节点提供了最小 minVal,方法是与您之前的 minVal(来自其他子节点、分支或 INT_MAX)进行比较.检查完所有子节点后,minValue返回给下一个父节点,与它的子节点进行比较,直到到达根节点。

    【讨论】:

    • 我认为这行不通。在这种情况下,minVal 包含不正确的值。
    • 很奇怪,我在您提供的解决方案链接上对其进行了测试,得到了相同的答案。让我尝试更多案例。
    • 我又试了几个案例都没有发现问题,你测试过还是发现了问题?这是我用来测试的那个:link。我还编辑了答案以解释其背后的逻辑。
    • 好吧,我的问题是:我们正在进行自上而下的遍历。由于我们正在为每个中间节点更新minVal,它不会只存储在中间节点遇到的最小值吗?
    • 看,这就是递归起作用的地方,你只有在到达叶子时才返回一个实际的新值。我对答案进行了更多编辑,以提供更深入的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-19
    • 2021-04-01
    相关资源
    最近更新 更多