【问题标题】:Understanding how recursion works with multiple returns了解递归如何处理多个返回
【发布时间】:2013-08-03 04:28:05
【问题描述】:

以下问题来自codingbat:给定一个整数数组,是否可以选择其中一些整数的一组,使得该组总和为给定的目标?

本站作者提供了如下解决方案:

public boolean groupSum(int start, int[] nums, int target) {
  if (start >= nums.length) return (target == 0);
  if (groupSum(start + 1, nums, target - nums[start])) return true;
  if (groupSum(start + 1, nums, target)) return true;
  return false;
}

假设我想尝试以下情况,其中 nums=[2,4,8] 并调用 groupSum(0,nums,10)。

我看到groupSum(0,nums,10) 将调用groupSum(1,nums,10)groupSum(1,nums,8)

groupSum(1,nums,10) 调用 groupSum(2, nums,10)groupSum(2, nums,6)

groupSum(1,nums,8) 调用 groupSum(2,nums,8)groupSum(1,nums,4)

等等……

通过代码我看到以下调用:

groupSum(3,nums,10)
groupSum(3,nums,2)
groupSum(3,nums,6)
groupSum(3,nums,-2)
groupSum(3,nums,8)
groupSum(3,nums,0)
groupSum(3,nums,4)
groupSum(3,nums,-4)

我看到 groupSum(3,nums,0) 应该返回 true,因为第一行:
if (start >= nums.length) return (target == 0); 但我对像 groupSum(3,nums,-4) 这样的其他调用感到困惑。从第一行开始,由于target != 0,它应该明显导致错误。

也有人可以解释为什么在

中 return true 语句是必要的
if (groupSum(start + 1, nums, target - nums[start])) return true;

我以为第一行就能判断真假。

if (groupSum(start + 1, nums, target)) return true;

【问题讨论】:

  • 这是递归!你认为它有意义吗??
  • 我希望 groupSum(3,nums,4) 不是由 groupSum(3,nums,0) 调用的,而是从另一个较早的调用。您可以添加第四个变量来查看被调用者 - 将 start+'_'+target 添加到每个调用中,然后将其打印出来以查看它的来源。

标签: recursion


【解决方案1】:

基本上这个功能可以分解成这样:

  1. 如果“开始”(数字数组中的当前位置)是数组末尾的一部分(换句话说,如果我们已经尝试了所有数字),那么函数成功,如果目标已达到(即为零)

  2. 否则,继续迭代 (start+1) 并包含当前编号 (target-nums[start]),如果可行则返回 true

  3. 否则,包括当前编号不起作用,因此继续迭代而不使用当前编号。如果可行,请返回true

  4. 如果我们已经到了这一点,那么没有办法添加有效的数字,所以返回false

您已经分解了所有可能的函数调用的步骤,并且正如您所观察到的,有一个返回 true(目标为零的那个)。这个true 结果级联备份递归成为最终返回值。

以下是其工作原理的粗略细分:

groupSum(0,[2,4,8],10)
0 >= 3? no, so continue:
groupSum(1,[2,4,8],10-2)?
  1 >= 3? no, so continue:
  groupSum(2,[2,4,8],8-4)?
    2 >= 3? no, so continue:
    groupSum(3,[2,4,8],4-8)?
      3 >= 3? yes. -4 == 0? no, return false
    groupSum(3,[2,4,8],4)?
      3 >= 3? yes. 4 == 0? no, return false
    return false
  groupSum(2,[2,4,8],8)?
    2 >= 3? no, so continue:
    groupSum(3,[2,4,8],8-8)?
      3 >= 3? yes. 0 == 0? yes, return true
    yes, return true
  yes, return true
yes, return true

希望这会有所帮助!

【讨论】:

  • 我明白你的意思了。谢谢!
  • 有点困惑 :( 请帮忙,如何比较 target == 0 将检查组总和与给定目标。
  • @prdp89 因为每次迭代都是从目标中减去当前测试值(以获得剩余的值),如果为 0 则匹配。因为如果a == b 那么a - b == 0
【解决方案2】:

除了 Kolink 的详细演练之外,对于它的价值,我在 Java 中创建了这个以帮助我了解:

public class TestRecursion{

    public static boolean groupSum(int start, int[] nums, int target, String s) {
        System.out.println(new String(new char[start]).replace("\0", "    ")+"start="+start+" target="+target+" parent="+s);
        if (start >= nums.length) return (target == 0);
        if (groupSum(start + 1, nums, target - nums[start], "A:"+start+"_"+target)) return true;
        if (groupSum(start + 1, nums, target, "B:"+start+"_"+target)) return true;
        return false;
    }

    public static void main(String... args){
        int[] nums = {2,4,8};
        groupSum(0, nums, 10, "");
    }
}

哪个输出:

start=0 target=10 parent=
    start=1 target=8 parent=A:0_10
        start=2 target=4 parent=A:1_8
            start=3 target=-4 parent=A:2_4
            start=3 target=4 parent=B:2_4
        start=2 target=8 parent=B:1_8
            start=3 target=0 parent=A:2_8

【讨论】:

  • 欢迎您。我还只是在代码中添加了缩进生成以使其更清晰。
猜你喜欢
  • 1970-01-01
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
  • 2018-03-28
  • 2018-07-18
  • 2018-05-13
  • 2014-05-23
  • 1970-01-01
相关资源
最近更新 更多