Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对集合中的项目求和以获得目标值的方法的数量-顺序很重要_Java_Algorithm_Search_Combinations_Permutation - Fatal编程技术网

Java 对集合中的项目求和以获得目标值的方法的数量-顺序很重要

Java 对集合中的项目求和以获得目标值的方法的数量-顺序很重要,java,algorithm,search,combinations,permutation,Java,Algorithm,Search,Combinations,Permutation,我正在练习编程面试,我在GlassDoor上偶然发现了一个问题:“找出我们可以对集合中的项目求和的方法,以获得我们的目标值。顺序很重要。” 显然,面试官无法给出答案,但他在GlassDoor上留下了这样的评论:“这更多的是一个数学问题,而不是一个编程问题。” 此问题似乎与此问题不同: 所以我的问题是:考虑到顺序的重要性,解决这个问题的正确方法是什么?还有,一个有效的算法是什么,可以解决所有方法求和集合中的项目以达到目标值的问题,以及排序问题 如果你能提供工作代码,那就太棒了。另外,我在用Java

我正在练习编程面试,我在GlassDoor上偶然发现了一个问题:“找出我们可以对集合中的项目求和的方法,以获得我们的目标值。顺序很重要。”

显然,面试官无法给出答案,但他在GlassDoor上留下了这样的评论:“这更多的是一个数学问题,而不是一个编程问题。”

此问题似乎与此问题不同:

所以我的问题是:考虑到顺序的重要性,解决这个问题的正确方法是什么?还有,一个有效的算法是什么,可以解决所有方法求和集合中的项目以达到目标值的问题,以及排序问题

如果你能提供工作代码,那就太棒了。另外,我在用Java练习,所以我更喜欢Java解决方案,但任何语言都可以

非常感谢。

使用动态规划。假设我们有项目
[1,2,3,4,5]
,目标是
10
。为了解决这个问题,我们将使用子集
[1]
[1,2]
计算从0到10的任何值的目标方法数<代码>[1,2,3,4,5]

那么,如果我们已经知道了用
[1,2,3]
对0到10之间的任何值求和的方法的数量,该怎么办?如何获得将任意值与另一项求和的方法数:
[1,2,3,4]
?这很简单:我们不能简单地包含这个新项目:它是所有以前的值。对于每个目标值x,前面的集合“[1,2,3]”中增加了一个路径数=路径数目标值(x-4):让我们用表来说明:

| sum | 1 | 2 | 3 | 4     |
|   1 | 1 | 1 |(1)| 1     |
|   2 | 0 | 1 | 1 | 1     |
|   3 | 0 | 1 | 2 | 2     |
|   4 | 0 | 0 | 1 | 1     |
|   5 | 0 | 0 |(1)|(1)+(1)| - this means that we can target 5 with 1 way
|   6 | 0 | 0 | 0 | 0 + 1 | from set `[1,2,3]` and 1 way to achieve 5 - 4 
|   7 | 0 | 0 | 0 | 0 + 2 | with the same set `[1,2,3]
|   8 | 0 | 0 | 0 | 0 + 1 |

而且很容易得到初始值。对于第1项,我们只能针对1项。

这就像是一个改变问题,但你不想要最小数量的“硬币”,你想要跟踪方式的数量。此外,重要的是要注意顺序很重要。使用动态规划如下。假设我们想展示如何从1,3,5的和中得出10,其中顺序无关紧要(即1+3+1+5与1+1+3+5相同)。制作一个索引为10(11项)的数组。你可以用一种方法得到00。所有负索引都可以用0种方式创建

00 01 02 03 04 05 06 07 08 09 10
 1
然后,您可以计算出1的方法数。如果你从1中减去硬币价值1,你得到1。如果你从1中减去任何较大的硬币价值,你会得到一个负指数,这意味着零。将结果加总为1路(减1)+0路(减3)+0路(减5)。所以我们有

00 01 02 03 04 05 06 07 08 09 10
 1  1
取值2。我们可以减去1分硬币得到1,其中有一种方法;3分硬币获得-1,其中有0种方式;5分硬币-3分,其中有0种方式。总共1+0+0=1种方式获得2美分

00 01 02 03 04 05 06 07 08 09 10
 1  1  1
对于3美分,我们可以减去1美分,以获得2美分的所有更改方式;或者减去3美分,以获得0美分的所有更改方式;或者减去5美分,以获得-2美分的所有更改方式;方法之和为1+1+0=2

00 01 02 03 04 05 06 07 08 09 10
 1  1  1  2
只需4美分,我们就可以用2+1+0=3种方式完成。但是,请注意,这三种方式包括1+1+1+1、3+1和1+3。1+3和3+1属于不同的类别,因为它们以不同的数字结尾

继续以这种方式,我们有

 00 01 02 03 04 05 06 07 08 09 10
  1  1  1  2  3  5  8 12 19 30 47
现在我们知道了如何构造数字,我们可以寻找更快的方法。请注意,我们必须处理前几个的负指数,这有点混乱,因此我们不妨从给定的前5个值开始。我们现在需要计算的是一个递归函数:
f(n)=f(n-1)+f(n-3)+f(n-5)
,条件是
f(0),…,f(4)
由上表给出

有很多方法可以计算递归函数。这就是它成为对知识深度的真正考验的地方。天真的方法是在编程语言中使用递归。第一个问题是您的数字将溢出,因为
f
呈指数增长。您可以使用
long
而不是
int
暂时缓解这种情况。但是
long
也会很快溢出,所以您必须使用biginger来获得大于(我猜)20左右的n的精确结果

其次,使用递归函数会很慢,因为计算
f(n)
可能需要反复计算较小的
f(x)
。要缓解该问题,请使用memonization存储较小值的
f(x)
。接下来,如果您尝试从较大的
n
计算到较小的值,您将遇到堆栈溢出。如果要计算特定的
n
,则应该从较低的值开始计算,而不是从较高的
n
值开始计算

接下来,您将体验内存不足。你可以通过在
x
增加时不记住
f(x)
的每一个值,而只记住最后的
5
值(在我的示例中)来解决这个问题。最终你会遇到存储大整数的内存不足的问题,但除非问题发生变化,否则你对此无能为力

如果你想提高程序的速度,可以使用更多的加速
f(n)
可以在
logn
操作中计算,而不是按以下方式在
n
操作中计算。注意,有一种写递归的矩阵乘法方法,在每个阶段,我们需要记住5个值来计算下一个值:

 |1 0 1 0 1| |f(n-1)|   | f(n) |
 |1 0 0 0 0| |f(n-2)|   |f(n-1)|
 |0 1 0 0 0| |f(n-3)| = |f(n-2)|
 |0 0 1 0 0| |f(n-4)|   |f(n-3)|
 |0 0 0 1 0| |f(n-5)|   |f(n-4)|
所以我们可以计算f(n)如果我们可以计算矩阵的幂:

 |1 0 1 0 1|^(n-4)
 |1 0 0 0 0|
 |0 1 0 0 0|
 |0 0 1 0 0|
 |0 0 0 1 0|
我们可以通过使用
n
的二进制扩展来加速这一过程。假设
n=6
,就像我们想要
f(10)
一样。请注意,二进制格式的
6=4+2
。用
M
表示矩阵。我们有
M^1
。我们计算
M^2=M^1*M^1
M^4=M^2*M^2
,然后
M^6=M^2*M^4

可能还有其他的加速,依情况而定