这是一个麻烦的问题:
我们得到了一个int数组。我们需要将数组压缩为单个int。每次压缩会将两个整数加在一起。压缩返回的值被推回到“需要压缩”组中,并添加到所有压缩的运行总和中。因此,目标是在阵列完全压缩后具有最小的总和。如果我没有道理,请举一个例子:
————
To Be Compressed Runningsum sum
[5, 12, 9, 15] -> 5 + 9 = 14. 0+14 = 14
[14, 12, 15] -> 14 + 12 = 26. 14+26 = 40
[26, 15] -> 26 + 15 = 41. 40+41 = 81
[41] -> Done
所以这里是81。
————
仅出于完整性考虑。这是一个错误的解决方案:
To Be Compressed Runningsum sum
[5, 12, 9, 15] -> 5 + 12 = 17. 0+17 = 17
[17, 9, 15] -> 9 + 15 = 24. 17+24 = 41
[17, 24] -> 17 + 24 = 41. 41+41 = 82
[41] -> Done
因此,此处82不是最佳的总和。
————
我了解如何通过执行double for循环并在每个内部循环中找到数组中的下一个最小值来实现这种蛮力O(n ^ 2)。然后在外部循环中,将运行总和设置为自身+刚找到的最小值,然后将运行总和添加到总和中。
findminimum() //5
runningsum=runningsum + 5
sum=0
findminimum() //9
runningsum=runningsum + 9 //5+9=14
sum+=runningsum //0+14=14
findminimum() //12
runningsum=runningsum + 12 //14+12=26
sum+=runningsum //14+26=40
findminimum() //15
runningsum=runningsum + 15 //26+15=41
sum+=runningsum //40+41=81
return sum
这可行,但是显然O(n ^ 2)并不是最好的。
接下来,您可以对数组进行合并排序。由于数组已排序,因此我们不必执行第二个for循环来查找上面的下一个min或findminimum()。因此,我们可以在单个for循环中执行运行总和并将数学求和。这将是O(nlog(n))。
所以我的问题是,您是否都在O(n)中看到任何实现此目的的方法,或者nlogn似乎是最好的可能性?我可能不熟悉一些数学公式来解决这个问题。
如果不清楚,我很乐意指定。谢谢您的时间!
答案 0 :(得分:1)
如果您的最小运行时确实受您的排序的约束,那么经典的比较排序将证明您的O(nlogn)充其量。
关键字有一个“比较”排序。
如果您完全熟悉线性时间排序,那么这里可能对您有用。
This link describes what's called a counting sort for example.
它的解释工作比我在这里可以做的要好得多。本质上,您分配了一个大小为max(arrtoMinSum)的数组,然后为arrToMinSum中的每个元素,在该索引处增加数组值。在该分配的数组上求和后,您将遍历原始数组,并将分配的数组中的值用作索引,以将原始数组中的每个值存储在最终输出数组中。我强烈建议您通读它,而不要根据我的解释进行实施。
由于您创建了一个大小为max(arrToMinSum)的数组,并遍历了数组和原始数组,因此运行时将为O(max(max(arrToMinSum),n)
。 (在很多情况下)这比比较排序要快(以更多的内存使用为代价)。
答案 1 :(得分:1)
我认为您的优化方法还不够。想象以下输入:
[4、5、7、8、10]
在这种情况下,您已经有一个订购列表。我们还假设它是作为二叉树实现的-因此搜索为O(log(n))。
现在添加4和5。结果9不是下一个求和运算的操作数。因此,您必须将其插入排序后的列表中,即O(log(n))。
因此,即使具有已排序的列表,您也具有O(n * log(n))。
所以不能达到O(log(n))的复杂度的原因是,您的总和n依赖于总和n-1,并且该结果的排序在其余输入中。因此,添加n * a [0] +(n-1)* a [1] ...的方法不会成功。