我需要了解这种递归是如何工作的,我理解简单的递归示例,但更高级的示例很难。即使只有两行代码,我也会遇到return
语句本身的问题。我只是画了一个关于它如何工作的空白,特别是和/或运算符。任何见解都是非常受欢迎的。
bool subsetSumExists(Set<int> & set, int target) {
if (set.isEmpty()) {
return target == 0;
} else {
int element = set.first();
Set<int> rest = set - element;
return subsetSumExists(rest, target)
|| subsetSumExists(rest, target - element);
}
}
答案 0 :(得分:5)
递归代码通常与缩减的概念相结合。通常,减少是通过某种变换将未知问题减少到已知问题的手段。
让我们来看看你的代码。您需要查找是否可以从输入数据集的元素构造给定的目标总和。 如果数据集为空,除了将目标总和与0进行比较之外,无需做任何事情。
否则,让我们应用减少量。如果我们从集合中选择一个数字,实际上可能有两种可能性 - 所选择的数字参与你正在寻求的数量,或者它没有。这里没有其他可能性(涵盖所有可能性非常重要!)。实际上,只要您可以涵盖剩余数据的所有可能性,选择哪个数据元素并不重要。
第一种情况:该数字不参与总和。我们可以将问题减少到一个较小的问题,数据集没有被检查的元素和相同的目标总和。
第二种情况:数字参与总和。我们可以将问题减少到一个较小的问题,数据集没有被检查的元素,请求的总和减少了数字的值。
注意,此时您不知道是否有任何这些情况属实。你只需要继续减少它们,直到你得到琐碎的空案例,你可以确切地知道答案。
如果对于这两种情况中的任何一种情况都是如此,原始问题的答案都是正确的。这正是operator ||
所做的 - 如果它的任何操作数(2个案例的结果)都为真,它将产生true。
答案 1 :(得分:3)
||
是符合逻辑的OR。它从左到右进行评估并短路。
这意味着在表达式A || B
中,首先评估A
。如果是true
,则整个表达式为true
,并且不会进行进一步的评估。如果A
为false
,则评估B
,并且表达式的值为B
。
在您的示例中,A
是“尝试在不使用集合中的第一个元素的情况下获得相同的总和”。 B
是“使用集合中的第一个元素,它将总剩余减少为总和,并尝试将其与元素的其余部分一起使用。”
答案 2 :(得分:2)
让我们先看看算法..
基本情况(即递归终止的情况)是集合为空时。
否则程序会将第一个元素从集合中减去。
现在它将调用subsetSumExists(rest, target)
并检查其是否为真,
如果是,它将返回true,否则它将调用
subsetSumExists(rest, target - element)
并返回任何内容
回报。
简单来说,只有当第一个subsetSumExists(rest, target - element)
返回false时,才会调用subsetSumExists(rest, target)
。
现在让我们尝试使用{3,5}的小样本集和8的总和来运行此代码。我将从现在开始调用函数sSE
sSE({3,5}, 8) => "sSE({5}, 8) || sSE({5},(8-3))"
sSE({5}, 8) => sSE({}, 8) || sSE({}, (8-5))
sSE({}, 8) => false.. now will call sSE({}, (8-5))
sSE({}, 3) => false.. now will call sSE({5}, (8-3))
sSE({5}, 5) => sSE({}, 5} || sSE({}, (5-5))
sSE({}, 5) => false.. now will call sSE({}, (5-5))
sSE({}, 0) => true.. ends here and return true
答案 3 :(得分:1)
要了解递归,您需要低估递归。 要做到这一点,你需要反复思考。
在这种特殊情况下。
对于任何:subsetSum(set, target)
如果set
为空且target
为0,则subsetSum
存在
否则,请删除set
的第一个元素。检查subdetSum(set, target)
是否存在或subdetSum(set, target - removed_element)
是否存在(使用步骤0)
答案 4 :(得分:1)
set减法看起来很奇怪,但我认为它意味着元素上的pop()。
虽然它是指数级的,但通过找到所有可能的组合“起作用”。
在||
语句中,LHS是包含当前元素的总和,RHS是除去它的总和。因此,您可以在指数树下,打开或关闭每个元素的每个组合。
顺便说一下,指数意味着如果你有30个元素,它将产生2到30的幂,即0x40000000
或接近10亿个组合。
当然你可能会用完记忆。
如果找到解决方案,则可能无法通过所有2 ^ N个案例。如果没有解决方案,它将始终全部访问它们。
答案 5 :(得分:0)
如果我为自己说话,那么对问题的理解将源于||
运算符。让我们用另一种方式看一下相同代码的底部return语句,
if (subsetSumExists(rest, target - element))
return true;
if (subsetSumExists(rest, target))
return true;
return false;