使用分而治之的最小前缀数组

Posted

技术标签:

【中文标题】使用分而治之的最小前缀数组【英文标题】:Min-prefix-array using divide and conquer 【发布时间】:2021-11-27 21:50:52 【问题描述】:

我正在努力解决一个分而治之的问题,因为我无法完全理解它。 假设我们有一些数组X[1:n]。我们如何找到最小前缀数组X[1:k],其中1 ≤ k ≤ n 和前缀被定义为X[1]×X[2]×...×X[n] 的实数数组?

到目前为止,我的方法是:

function min_prefix(array[1:n],n)
begin
    if array.length == 1 then
        return n, array[0], array[0]
    endif
    
    
integer best_k, real b_total, total = min_prefix([1:n-1],n-1)

new_total = total*array[n]

if  new_total < b_total then
    return n, new_total, new_total
endif

return best_k, b_total, new_total
    end

我不认为这是一个有效的分而治之的解决方案,因为我仍然需要遍历数组中的每个元素。

编辑:

我能想到的最好的例子:

考虑数组-1,2,2,2,最小前缀为k=3,因为当所有元素相乘时,结果答案为-6。

但是,如果我们再考虑数组-1,2,-2,2,那么最小前缀将是k=1,因为k[0]*k[1] = -2 乘以第三个元素只会使数字更大。

【问题讨论】:

一定要“分而治之”吗?对于未排序的数组,我认为不可能在少于线性的时间内得到答案。 @Aivean 是的,它必须分而治之:/ @don'ttalkjustcode 修复了混淆并添加了示例 好,虽然你的例子有一些错误,例如k[0]是双重错误,我认为应该是X[1] 而且“前缀产品”似乎是正确的术语。 【参考方案1】:

找到“最小前缀积”的算法基本上是计算所有可能的前缀并找到其中的最小值。这可以在线性时间内完成,而不是更快。

伪代码:

min_pref_l = 1
min_pref_v = arr[0]
prev_f = arr[0]

for i in 1 until arr.length:
  pref_v *= arr[i]
  if pref_v < min_pref_v:
    min_pref_v = pref_v
    min_pref_l = i + 1

return min_pref_v, min_pref_l

问题中最奇怪的部分是“分而治之”的要求。我想,如果你眯着眼睛看这个算法,你可能会说,它是“分而治之”,至于计算长度为i的前缀,它使用了之前计算的长度为i-1的前缀。

为了说明这一点,可以将算法重写为递归函数:

# min_prefix returns tuple of three values:
# First two define the minimal prefix of length ≤ i, as the pair of (value, length)
# Third is the product of the prefix of length i
fun min_prefix(i: int) -> (int, int, int):
   if i == 0:
     return arr[0], 1, arr[0]
   
   prev_min_l, prev_min_v, prev_v = min_prefix(i-1)
   v = prev_v * arr[i]
   if v < prev_min_v:
     return i+1, v, v
   else:
     return prev_min_l, prev_min_v, v

# program result
return min_prefix(arr.length - 1)

注意:

在递归变体中,空间复杂度从 O(1) 变为 O(n),函数可以重写为尾递归以避免这种情况 为了简化代码,没有刻意考虑诸如空数组和产品溢出等极端情况

【讨论】:

以上是关于使用分而治之的最小前缀数组的主要内容,如果未能解决你的问题,请参考以下文章

使用分而治之的范式提高算法效率

用于查找数组中最小值的分治算法

使用分而治之的方法找到最大值和最小值

如何在未排序数组的情况下找到未排序数组中的第k个最小整数?

两个大小为 n 的数据库中的第 n 个最小数字,每个数据库都使用分而治之 [关闭]

总和大于或等于 k ​​的最小子集