给定一个int数组和一个数n,计算使用整数求和的方法数

时间:2016-07-18 20:49:03

标签: algorithm recursion

我在面试准备中看到了这个问题。

  

给定一个int数组和一个数n,计算方法的数量   使用整数

加总到n

以下代码是我的解决方案。我试图通过递归来解决这个问题。子问题是针对数组中的每个int,我们可以选择与否。

public static int count(List<Integer> list, int n) {
    System.out.print(list.size() + ", " + n);
    System.out.println();
    if (n < 0 || list.size() == 0)
      return 0;
    if (list.get(0) == n)
      return 1;
    int e = list.remove(0);
    return count(list, n) + count(list, n - e);
  }

我尝试使用[10,1,2,7,6,1,5]进行整数,并将n设置为8.结果应为4.但是,我得到0.我试图打印我有的东西在每个堆栈层上进行调试,如代码所示。以下就是我所拥有的:

7, 8
6, 8
5, 8
4, 8
3, 8
2, 8
1, 8
0, 8
0, 3
0, 7
0, 2
0, 1
0, 6
0, 7
0, -2

这个结果让我很困惑。我认为它从开始到(0,3)看起来正确。从(0,7)开始,我看起来不对。我期待(1,7)那里。因为如果我理解正确的话,那就是对于堆栈底层的第二次调用count(list,n-e)。下层的列表操作不应影响当前层上的列表。 所以我的问题是:

  1. 为什么(0,7)而不是(1,7)基于我当前的代码?
  2. 我应该对当前代码进行哪些调整才能获得正确的结果?
  3. 谢谢!

1 个答案:

答案 0 :(得分:5)

您的算法无法正常工作的原因是因为您正在使用一个在递归调用之前被修改的列表。

由于列表通过引用传递,最终发生的是你递归调用remove,直到列表中没有任何内容,然后你的所有递归调用都将继续返回0

您可以做的是在每个递归步骤中创建列表的两个副本。但是,这样效率太低了。

更好的方法是使用索引i来标记在调用期间正在查看的列表中的元素:

public static int count(List<Integer> list, int n, int i) {
    //System.out.print(list.size() + ", " + n);
    //System.out.println();
    if (n < 0 || i <= 0)
      return 0;

    int e = list.get(i);  // e is the i-th element in the list
    if (e == n)
      return 1 + count(list, n, i-1);   // Return 1 + check for more possibilities without picking e

    return count(list, n, i-1) + count(list, n - e, i-1);   // Result if e is not picked + result if e is picked
}

然后,您将在初始函数调用中为yourList.size() - 1传递i

还有一点是,当您return 1时,您仍需要添加元素e未被选择作为总和的一部分的可能性。否则,如果 - 例如 - 列表中的最后一个元素是n,则递归将在第一步结束,仅返回1而不检查更多可能的数字组合。

最后,您可能希望使用动态方法重写算法,因为这样可以提供方式更好的运行时间。