【问题标题】:Pick from array which is equal to some number从等于某个数字的数组中选择
【发布时间】:2016-08-24 10:24:19
【问题描述】:

我有一个类似这样的金额数组:

[ 100, 20, 80, 50, 150, 20, 10 .. ]

我必须从这个数组中选择一个数量,比如 200。

所以,数量将是 150,从数组中选取 50。

我可以构建一个算法,它可以一次又一次地遍历数组并检查数量是否相等,但我想知道是否有简单的方法?

或者我必须在循环中编写一个算法匹配并挑选和检查?

谢谢。

示例说明:

我有一个数组。 说 -> 100、200、300

我有另一个数组。 说 -> 50,50,20,10,20,150,150,50,70,30

我想通过从第一个数组中选取一个数字(即 100)进行匹配,如果匹配,则通过第二个数组中的数字总和进行匹配,否则很好,我将跳过它并尝试下一个数字(即200) 在数组中。

编辑:一些说明

数组不包含完全匹配。我之前匹配它并从数组中删除。所以它只包含可以完全相同的数字。

如果任何金额与给定金额不匹配,那很好。如果数组中的总和不匹配,我将跳过。

【问题讨论】:

  • 您确定总能准确得出总和吗?
  • 如果只有数字 A,如果它等于数字 A,则选择数字 A 是无稽之谈。您想从列表中删除它吗?
  • 你刚才描述的是简单的方法。我的意思是...有很多方法可以提供更好的运行时间,但是您描述了蛮力方法,这始终是最容易提出和实施的方法,因为它涉及的思考很少:D
  • 您向我们提供了“应该是什么”的不完整、模糊的描述,没有显示代码,您希望我们解决它吗?

标签: java arrays algorithm


【解决方案1】:

您尝试解决的问题称为subset sum problem,属于NP-complete 问题。

给定一组整数和一个整数 s,任何非空子集 和 s (...)

没有多项式时间算法可以解决这个问题已知(目前;))。
如果您的集合包含 n 元素,您可以检查集合的所有子集 O(2^n)
最终,如果您的集合是无限集合,您可以尝试求解 change-making problem


仍然可以解决(我上面写的指数复杂性)。考虑一个函数:

bool foundSum(set[], n, sum);

如果可以找到总和则返回true,否则返回false。一个简单的递归算法:

foundSum(set,n,sum) = foundSum(set,n-1,sum) or foundSum(arr,n-1,sum-set[n-1])

它是如何工作的?在每个步骤中,您检查是否可以在您加入/排除最后一个元素时获得总和

用 C++ 实现的示例(可以很容易地用 Java 编写):

bool foundSum(vector<int> set, int n, int sum) {
    if(sum == 0) return true;
    if(n == 0 and sum != 0) return false;

    int last = set[n-1];

    if(last > sum) return foundSum(set, n-1, sum);
    return foundSum(set,n-1,sum) or foundSum(set,n-1,sum-last);
}

修改为找到答案时打印子集:http://ideone.com/YysY2n

【讨论】:

  • 我真的不是递归函数调用的忠实粉丝。我无法理解其中的大部分内容。我正在检查输出,目前对我来说似乎很好:tutorialspoint.com/…。如何包含导致此返回 true 的数字?如果可能的话,我会得到一笔钱。如果可能的话,你能解释一下或指出我在哪里可以理解这种递归函数吗?
  • 每个递归算法都可以写成迭代算法,但通常递归算法更容易实现(就像在这种情况下)。怎么理解?我推荐一支铅笔和一张纸。
  • 看看(按您的要求打印子集):ideone.com/YysY2n
  • 铅笔和纸永远是最好的东西!您的 ideone 代码在该站点上运行良好,但在 tutorialspoint 上没有打印任何内容!
  • 我终于明白了。画了这么多图,终于明白了。我正在创建一个从前面开始的稍微修改过的版本。兴奋的!感谢精彩的功能!
【解决方案2】:

算法:

def solve(subList: List[Int], ammount: Int) = ammount match {
  case 0 => true
  case _ => sublist match {
    case Nil => false 
    case x::xs => {
      val rest = ammount - x
      solve(xs, ammount) || rest >= 0 && solve(xs, rest)
    }
  }
}


solve(list, ammount)

解释:

你可以在list中获取ammount

  1. 如果你取第一个元素并且可以在list without first element 中得到ammount - first element

  2. 如果你不取第一个元素,你可以在list without first element中得到ammount

所以我们对递归的每一步都有减少。

当 ammount 被收集时,我们以true 终止,当子列表为空且非零数量时,我们以false 终止。

示例: 从 (50,50,20,10,20,150,150,50,70,30) 需要 100: solve((50,50,20,10,20,150,150,50,70,30), 100)

我们可以,如果

solve((50,20,10,20,150,150,50,70,30), 100) == true || solve((50,20,10,20,150,150,50,70,30), 50) == true

下一步: 从 (50,20,10,20,150,150,50,70,30) 需要 50

solve((50,20,10,20,150,150,50,70,30), 50)

我们可以,如果

solve((20,10,20,150,150,50,70,30), 0) == true || solve((20,10,20,150,150,50,70,30), 50) == true

第一个是true => 终止

【讨论】:

  • 提示:无论如何都要解释一个算法。海报不是要复制粘贴,而是要理解。
  • 是什么语言的?
  • 它是 Scala。您所需要的只是正确的算法。你可以用Java实现它。
  • 谢谢谢尔盖!我花了一些时间来理解你的功能。起初我不明白,因为我不熟悉 scala。但是,是的,这也很有效。现在,我明白了。谢谢你的解释。
【解决方案3】:

我相信找出必须选择哪些索引才能达到总和的最佳方法是将数量排序在一个数组中。 (例如,如果可能的话,将它们排序)

然后您可以迭代直到达到总和,如果超过则中止。

但是,更多的上下文会有所帮助,因为这个任务似乎不是很有用..

【讨论】:

  • 是的,这就是我在我的一项职能中所做的。但是感觉有点复杂。排序后的数组是解决这个问题的必要条件。
  • 这不会涵盖所有的可能性。
  • 是的,我相信在这种情况下它确实与en.wikipedia.org/wiki/Knapsack_problem有关
【解决方案4】:
Find all the possible subsets and check If any of the subset sum 
will match with the target amount.

更新

Its better to calculate the sum immediately and checking after finding each subset. So that 
we could skip atleast few subsets finding them. 

【讨论】:

  • 2^n,一点也不差
  • 那很糟糕。想象一下,您有一个包含 100 个元素的列表。猜猜你能从那里得到多少个子集
  • 是 2^n,正如 Mateus 所说,猜猜 2^100 是多少
  • 这就是我使用字符串和浮点映射时的问题。性能
猜你喜欢
  • 2019-10-12
  • 2023-03-29
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多