将值从叶传播到根

Propagating values from the leaf to the root

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

How do you propagate values from the leaf to the root?

例如,假设我们有一棵二叉树,其中我们必须找到具有最小总和的根到叶的路径。对于树形图像 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 不正确 - 但我应该 return 做什么?从技术上讲,当我到达叶节点时,我只想 return minVal 的值(当我在中间节点时没有值)。那么,如何将 minVal 从叶节点传播到最顶层的 root 节点?

P.S.: 我正在准备面试,这对我来说是一个很大的痛点,因为我几乎每次都卡在这一点上。我将不胜感激任何帮助。谢谢。

编辑:对于这个特定的,我不知何故 wrote a solution 使用了引用传递。

在您的 for 中保存所有 children 和 return minVal 而不是 currVal 的 minVal

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

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

编辑:解释

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

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

一旦这个值被returned,我们回到调用它的函数,它在节点(5),恰好在我们调用(4)的时候,我们将(经过我的修改)比较它 returned 与 minVal 的任何值。

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

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

如果 (5) 有其他 children,我们现在将输入 dfs 的新实例,一旦我们得到结果,将该值与9,但因为我们不这样做,所以我们结束 for 循环和 return minVal,回到根节点(0 ).

从那里,我相信你能猜到会发生什么,我们进入节点(3)分支到(2)->(1)->(1)和(0)->(10),returning 7 和 13 分别进入 for 循环,节点 (6) 最终也会 return 7 到 (0) 的 for循环。

最后,(0) 会先比较 INT_MAX 和 9,然后比较 7,最后再比较 7,returning 7 to getCheapestCost.

简而言之:

你的代码会一直进入dfs直到它找到一个没有children的节点,一旦发生这种情况,它将return minVal 它从该节点获得,return 到调用它的函数,即 parent 节点。

进入 parent 节点后,您需要检查哪个 children 提供了最小值 minVal,方法是将其与之前的 minVal(来自其他children、分支或INT_MAX)。检查所有 children 后,minValue 被 returned 到下一个 parent,与它的 children 比较,直到达到根节点。