arrays - 需要解决这个算法难题的想法

标签 arrays algorithm split partition-problem

过去我遇到过一些与此类似的问题,但我仍然不知道如何解决这个问题。问题是这样的:

给你一个正整数数组,大小为 n <= 1000 且 k <= n,这是你必须将数组拆分成的连续子数组的数量。你必须输出最小的 m,其中 m = max{s[1],...,s[k]},s[i] 是第 i 个子数组的和。数组中的所有整数都在 1 到 100 之间。示例:

Input:                           Output:
5  3  >> n = 5 k = 3             3
2 1 1 2 3

将数组拆分为 2+1 | 1+2 | 3 将最小化 m。

我的蛮力想法是让第一个子数组在位置 i 结束(对于所有可能的 i),然后尝试以最佳方式将数组的其余部分拆分为 k-1 个子数组。但是,这是指数解决方案,永远不会奏效。

所以我正在寻找解决它的好主意。如果你有请告诉我。

感谢您的帮助。

最佳答案

你可以用动态规划来解决这个问题,但实际上你可以用贪心和二分搜索来解决这个问题。此算法的复杂度为 O(n log d),其中 d 是输出答案。 (上限是数组中所有元素的总和。)(或输出位大小中的 O( n d ))

这个想法是对你的 m 进行二进制搜索——然后在数组上贪婪地向前移动,将当前元素添加到分区,除非添加当前元素将它推到当前 m——在这种情况下,你开始一个新的分区。如果使用的分区数小于或等于您给定的输入 k,则当前 m 成功(并因此调整您的上限)。否则,您使用了太多分区,并提高了 m 的下限。

一些伪代码:

// binary search
binary_search ( array, N, k ) {
    lower = max( array ), upper = sum( array )

    while lower < upper {
        mid = ( lower + upper ) / 2

        // if the greedy is good
        if partitions( array, mid ) <= k
           upper = mid
        else
           lower = mid
    }
 }

 partitions( array, m ) {
    count = 0
    running_sum = 0

    for x in array {
       if running_sum + x > m
          running_sum = 0
          count++
       running_sum += x
    }
    if running_sum > 0
       count++
    return count
 }

这在概念上应该更容易提出。另请注意,由于分区函数的单调性,如果您确定输出 d 不是太大,您实际上可以跳过二进制搜索并进行线性搜索:

 for i = 0 to infinity
    if partitions( array, i ) <= k
       return i

关于arrays - 需要解决这个算法难题的想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8592143/

相关文章:

python - numpy.as_strided 的结果是否取决于输入数据类型?

sql - 通过过滤找出mysql中json数组中所有元素的总和

python - 我需要帮助使用包裹递送列表调整算法以找到最短路径

algorithm - 选择序列中的元素

linux - awk 如果表达式创建 0 和 1 而不是预期结果

java - 分割字符串并删除存储在数组中的逗号 - Java

java - 从字符串中提取 2 个整数

c++ - copy() 将除最后一个元素之外的所有元素从 vector 复制到数组 C++

c# - 将二维数组的二维数组转换为单个二维数组

c++ - 用 C++ 编写的 FASTA 阅读器?