我已经解决了很多与树相关的问题,但是,我仍然对树的一个特定方面(一般的递归)没有信心:
如何将值从叶传播到根?
例如,考虑我们有一个二叉树,其中我们必须找到具有最小总和的根到叶子路径。对于树图像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
节点?
编辑:对于这个特定的一个,我不知何故wrote a solution使用传递引用。
答案 0 :(得分:1)
在 for 中保存所有孩子的 minVal 并返回minVal而不是currVal。
for(auto& neighbor: rootNode->children) {
minVal = min(minVal, dfs(neighbor, minVal, currVal));
}
return minVal;
这样你总是会返回minVal,通过递归一直到第一次调用。
修改:说明
我将使用您在问题中提供的tree作为示例。我们首先在根(0)处输入树。它会向currVal添加0,不会输入第一个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)。
从那里,我相信你可以猜到会发生什么,我们进入节点(3),分支到(2) - &gt;(1) - &gt;(1)和(0) - &gt;(10),返回分别为 for 循环的7和13,节点(6)最终也会返回7到(0)的 for 循环。
最后,(0)首先将INT_MAX与9进行比较,然后再与7进行比较,最后再与7进行比较,将7返回到 getCheapestCost 。
简而言之:
您的代码将继续输入 dfs ,直到找到没有子节点的节点,一旦发生这种情况,它将返回从该节点获取的 minVal ,然后返回调用它的函数,即父节点。
进入父节点后,您需要检查哪些子项提供了最小 minVal ,方法是将其与之前的 minVal (来自其他子级,分支机构或INT_MAX)进行比较。检查完所有子项后, minValue 将返回到下一个父项,后者将与其子项进行比较,直到它到达根节点。