可被n整除的最大和


16

在StackOverflow上问了这个问题,但我认为这是一个更合适的地方。

这是算法概论课程中的一个问题:

您有a包含n正整数的数组a(该数组无需排序或元素唯一)。建议使用O(n)算法查找可被整除的元素的最大和n

例如: a=[6,1,13,4,9,8,25],n=7。答案是56(与元件6,13,4,8,25

这是比较容易找到它O(n2)使用动态编程和存储与余最大的一笔0,1,2,...,n1

另外,如果我们将注意力集中在元素的连续序列上,则可以通过存储部分和以n为模的总和来轻松地在O(n)时间内找到最佳的此类序列:让S [ i ] = a [ 0 ] + a [ 1 ] + + 一个[ ],对于每个剩余ř记住最大索引Ĵ使得小号[ Ĵ ] řnS[i]=a[0]+a[1]++a[i]rjS[j]r(modn)iS[j]S[i]jr=S[i]modn

但是对于一般情况,是否有时间解?任何建议将不胜感激!我认为这可以解决线性代数问题,但是我不确定到底是什么。O(n)

或者,可以在时间内完成此操作吗?O(nlogn)


2
1.您已经在Stack Overflow上发布了完全相同的问题。请不要在多个站点上发布相同的问题。我们不希望多个副本在多个SE网站上浮动。如果您没有得到可接受的答案,可以标记要迁移到另一个站点的问题,但是请不要只是在其他地方重新发布相同内容。2.您能给出现该问题的教科书或课程提供参考/引用/链接吗?您如何确定确实存在时间解决方案?O(n)
DW

5
您的大学面临的挑战仍然存在吗?看到与课程的链接,确切的问题真的很有帮助,如果确实是并且准备课程的人将解释/发布他们的答案,那将很棒。O(n)
邪恶的

使用动态编程在O(n2)O(n2)中找到它并存储剩余的最大总和为0,1,2,...,n-10,1,2,...,n-1相对容易。您能详细说明一下吗?我可以理解,如果仅考虑连续元素,而又考虑到非连续元素,这将是n平方的,不是按顺序指数的吗?
Nithish追逐幸福

Answers:


4

这里有一些随机的想法:

  • 动态编程算法可以翻转为寻找最小和而不是最大和。您只需要寻找与整个数组之和的余数相等的和,而不是与零相等的和。如果我们按递增顺序处理元素,则有时这会使动态算法在处理整个数组之前终止。

    如果我们处理k个元素,则成本为。有没有一个下界Ω ñ 登录ñ 对这个算法,因为我们没有对所有的元素进行排序。只需O n log k 时间即可得到k个最小的元素。O(nk)kΩ(nlogn)O(nlogk)k

  • 如果我们关心最大的集合,而不是总和最大的集合,则可以使用基于快速傅里叶变换的多项式乘法来解决时间。当域范围受到限制时,与3SUM中的操作类似。(注意:使用重复平方进行二进制搜索,否则将得到O n k log n log log n ,其中kO(n(logn)2(loglogn))O(nk(logn)(loglogn))k 是省略元素的数量。)

  • 是合成的,并且几乎所有余数都是n因子之一的倍数时,通过关注不是该因子倍数的余数可以节省大量时间。nn

  • 当剩余物r很常见或仅有少量剩余物时,如果您从此处开始并继续前进,则跟踪“下一个空位r”信息可以节省大量的跳跳到空位时间。

  • 您可以通过仅跟踪可达性并使用位掩码(在翻转的动态算法中)来剃除对数因子,然后在达到目标余数时回溯。

  • 动态编程算法非常适合并行运行。使用每个缓冲区的处理器,您可以降低到。或者,通过使用O n 2宽度,并用分治法聚合而不是迭代聚合,电路深度成本可以一直降至O log 2 n O(n)O(n2)O(log2n)

  • (元)我强烈怀疑给您的问题与连续的和有关。如果您链接到实际问题,将很容易进行验证。否则,鉴于该问题是在名为“算法简介”的课程中分配的,我对该问题的困难程度感到非常惊讶。但是也许您在课堂上讲过一个使它变得微不足道的技巧。


对于第一点。它没有写在问题的规范中,所以您不能假设这一点。而且,问题不是说您不能修改数组或创建新数组,实际上可以。你需要做的唯一的事情就是发现加在一起给你的是整除的最大的一笔数字Ø ñ 的时间复杂度(通常它的假设只是时间复杂度)。nO(n)
nbro

2
@EvilJS在除去总和最小的子集后,其余数为0的子集最大且等于0的子集等于该子集。查找与相等的最小和比查找与r 2相等的最大和更方便,因为它使您可以在找到解后立即终止(当按递增顺序处理元素时),而不必继续。r1r2
克雷格·吉德尼

-1

我提出的算法如下:

如果仅添加n的倍数的求和,则和可被n整除。

在开始之前,您需要创建一个哈希表,其中将int作为键,并将索引列表作为值。您还将创建一个包含索引的结果列表。

然后,您遍历数组,并将mod n为零的每个索引添加到结果列表。对于其他每个索引,请执行以下操作:

您从n中减去此索引的值mod n。此结果是哈希图的键,该键存储具有所需值的元素的索引。现在,您将该索引添加到哈希图中的列表中并继续。

完成对数组的循环之后,您将计算输出。通过根据索引所指向的值对哈希图中的每个列表进行排序,可以实现此目的。现在,您考虑哈希图中的每一对总计n。因此,如果n = 7,则在哈希表中搜索3和4。如果两者都得到一个条目,则采用两个最大值将它们从它们的列表中删除并将它们添加到结果列表中。

最后的建议:仍然没有测试该算法,使用蛮力算法针对它编写一个测试用例。


2
贪婪,线性,不起作用。您只考虑可被n整除的元素和可被n整除的元素对,三元组和更多元素呢?它不保证平凡情况下的最大子集和。[2,1,8] - >最大总和为9,但你的算法返回3.

@EvilJS您的sub 算法发生了什么?n2
三角洲终结者

感谢您指出这个错误给我。我的改进想法是制作一个列表堆栈的哈希图,该哈希图通过增加值来排序,并且仅在完成通过数组的传递之后才开始累积。
TobiasWürfl'3

您是说要对数组进行排序,并且“ hashmap”是%n?您仍然需要对它们进行排序,如果对它们进行了排序,则采用最小值/最大值是可以的,但实际上选择子集仍然有不可避免的一部分,这在最坏的情况下是无益的。无论如何,如果您有一些改进,也许您可​​以编辑帖子?
邪恶的

是的,使用堆栈很简单。实际上,您只需要在哈希图中排序的列表即可。我不确定编辑我的第一个答案是否礼貌。毕竟我在第一次尝试中犯了一个错误。
TobiasWürfl'3

-2

从(/programming/4487438/maximum-sum-of-non-consecutive-elements?rq=1)使用此DP方法:

给定一个数组A [0..n],令M(i)为使用索引为0..i的元素的最优解。然后M(-1)= 0(用于重复),M(0)= A [0],并且M(i)= max(M(i-1),M(i-2)+ A [i ])for i = 1,...,n。M(n)是我们想要的解决方案。这是O(n)。您可以使用另一个数组来存储为每个子问题做出的选择,从而恢复所选的实际元素。

将递归更改为M(i)= max(M(i-1),M(i-2)+ A [i]),以便仅在其可被N整除的情况下存储


2
这是行不通的-我让您找出原因。(提示:尝试在常量1数组上运行它。)此外,在此问题中,我们确实允许连续的元素。
Yuval Filmus

1
这是一个非常好的解决方案,可以解决完全不同的问题(并且容易得多)。
Evil
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.