素数长度的所有连续子数组的最大和

Posted

技术标签:

【中文标题】素数长度的所有连续子数组的最大和【英文标题】:Maximum sum of all contiguous subarrays of prime length 【发布时间】:2017-07-21 20:40:17 【问题描述】:

我最近在一次采访中被问到这个问题,

给定一个非负整数数组,找出 可以得到的最大累积总和,使得所有的长度 参与子数组是一个素数。我尝试使用动态编程提出解决方案,但不幸的是无法解决。

例如:如果数组是 [9,8,7,6,5,4,3,1,2,2] 它应该返回 46 (子数组的总和 [ 9,8,7,6,5,4,3] 长度为 7 和 [2,2] 长度为 2)。您不能将 [9,8,7,6,5,4,3] 和 [1,2,2] 组合起来,因为它会产生一个长度为 10 且非素数的连续子数组(幂等性)。

谁能解释如何使用 DP 解决这些问题?谢谢。

【问题讨论】:

为什么不是 15? [8,4,3] - 长度是质数 (3)。你没有说所有元素都应该是素数。 为什么要使用动态规划?很简单,就是先找到最大的素数(从列表的长度倒推),然后是那个特定长度的最大子数组,这是一个很常见的问题。 @user 它应该包含连续的元素。抱歉忘记提了。修好了! @ChatterOne 你能提供一个伪代码吗?我想我没听懂你说的。 对于一个大型数组,我认为您希望在遍历求和之前将其扫入segment tree。 【参考方案1】:

你可以做什么:

取列表的长度并返回,直到找到一个素数 获取元素窗口并求和 检查它是否是最大和,如果是,存储它 转到下一个窗口

这是因为所有整数都是正数的限制,否则它不会起作用。

基本上是这样的(非常粗略,在伪python中,显然没有经过测试):

input_list = (8, 1, 3, 4, 5, 2)
list_size = len(input_list)

while (list_size):
    if (is_prime(list_size)):
        window_size = list_size
        break
    list_size--

max_sum = -1
for i in xrange(0, list_size - window_size):
    current_sum = sum(input_list[i:i+window_size])
    if (max_sum < current_sum):
        max_sum = current_sum

print max_sum

【讨论】:

我的问题措辞有误,现在修正了。你能重新审视一下吗?谢谢。 用 (100,1,1,1,1,100) 测试它。它将返回总和为 104 的单个 5 元素子数组,但最大值为 203。 @n.m.那是因为问题明确表示“连续子数组”。 它没有。它说“几个不相邻的连续子数组的总和,每个子数组的长度都是素数”。 @n.m.我现在看到,自从我回答之后,这个问题发生了很大变化。我可能应该删除它。【参考方案2】:

像这样的(大约)O(n * n / log n) 时间、O(n) 空间、DP 怎么样?

f(i) 表示索引i 的最大总和,其中a[i] 要么被排除在连续子集中,要么是素数长度子集的最后一个。那么:

f(i) = sum(a[0]...a[i]) if (i + 1) is prime, otherwise
  max(
    // a[i] excluded
    f(i-1),
    f(i-2),

    // a[i] is last of a subset
    sum(a[i - primes[j] + 1]...a[i]) + f(i - primes[j] - 1) 
      for primes[j] <= i
  )

(对时间间隔求和可以在O(1) 时间内完成,对前缀和进行O(n) 预处理。)

【讨论】:

当 a[i] 是子集的最后一个时,你能解释一下递归的含义吗?或者更好的是,您能否解释一下您是如何得出外行术语的复发的?我不明白这意味着什么。谢谢:) @GeT_RiGhT 通过“子集”,我的意思是子数组。如果 a[i] 不是子数组的一部分,我们不会将其算作总和的一部分,因此在这种情况下,直到 i 的最大总和将是最大总和中的较大者,直到 (i-1) 或 ( i-2)。在那之后,我们处于 a[i] 可能是素数长度为 2 或更大的子数组的最后一个的情况。然后我们将这些可能性一一比较:如果它的长度为 2,我们将最大和 (i - 2 -1) 相加,即 f(i-2-1);如果是 5,我们将 f(i-5-1) 相加,以此类推。 如果 a[i] 不是子数组的一部分,为什么我们要考虑最大总和为 (i-1) 或 (i-2)?还有什么是 f(0)? @GeT_RiGhT 如果 a[i] 不是子数组的最后一个,那么直到 i 的最大总和将不包括 a[i],因此它将与之前的最大总和相同。我们还检查 (i-2),因为子数组之间必须有一个空格(但在 (i-3) 处,a[i] 可能是长度为 2 的子数组的最后一个,所以这是另一个检查开始的地方)。在我看来,f(0) 取决于您是否认为 1 是素数。我认为通常的约定是从 2 开始。【参考方案3】:

由于其他人已经解决了非负整数的问题。

但是如果你也有 -ve 数字,那么这个算法也可以工作。 我认为您必须稍微调整Kadane's Algo。

以下是修改后的 Kadane 算法的更改。所有标记为 ** 的行都是更改。

Initialize:
    max_so_far = 0
    max_ending_here = 0
   ** MAX_SO_FAR_FOR_PRIMES =0
   ** SUB_ARRAY_SIZE = 0

Loop for each element of the array
   max_ending_here = max_ending_here + a[i]
   ** SUB_ARRAY_SIZE = SUB_ARRAY_SIZE + 1 // since a[i] included in subarray, increase sub_array_size
  if(max_ending_here < 0)
            max_ending_here = 0
   **         SUB_ARRAY_SIZE = 0  
  if(max_so_far < max_ending_here)
            max_so_far = max_ending_here
   ** if(MAX_SO_FAR_FOR_PRIMES < max_ending_here && isPrime(SUB_ARRAY_SIZE)) // comparing when SUB_ARRAY_SIZE is Prime.
   **      MAX_SO_FAR_FOR_PRIMES = max_ending_here.    

return MAX_SO_FAR_FOR_PRIMES

基本上,再取一个变量MAX_SO_FAR_FOR_PRIMES,它保留了迄今为止素数子数组的最大和子数组。

还存储SUB_ARRAY_SIZE,它在循环期间随时存储子数组的大小。

现在只要SUBARRAY_SIZE 是质数,就将MAX_SO_FAR_FOR_PRIMESmax_ending_here 进行比较。并相应地更新 `MAX_SO_FAR_FOR_PRIMES1。

【讨论】:

对不起。我的问题措辞不正确。修复!我还能用 Kadane 的算法解决它吗? 我需要所有素数长度的连续子数组的累积总和。更新了问题。请看一看。谢谢

以上是关于素数长度的所有连续子数组的最大和的主要内容,如果未能解决你的问题,请参考以下文章

[算法导论]4.1-5最大连续子数组问题

给定一个数组和一个总和,找到小于总和的最大长度连续子数组

连续子数组的最大和

找到最大和连续子数组,使得子数组的长度小于等于 k?

#yyds干货盘点# 解决剑指offer:连续子数组的最大和

2022-05-06:给你一个整数数组 arr,请你将该数组分隔为长度最多为 k 的一些(连续)子数组。分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值。 返回将数组分隔变换后能够得到的元