假设我有一个可以使用这两个标准保存数字的组:
e.g。如果我有数字1,2,3,4,6,8,10,11,13,16,17,18
。如何在尽可能少的窗口中对这些数字进行分组?两个可能的答案:
[1,2,3,4],[6,8,10,11],[13,16,17,18]
[1,2,3],[4,6,8],[10,11,13],[16,17,18]
也许这不是最好的例子,但是有一个与此类似的编程问题吗?
答案 0 :(得分:1)
这对于动态编程来说不是一个好问题。一个贪婪的算法就足够了。
这是一个非常粗略的草图,证明贪婪就足够了。
(remark-1)假设[x1, x2, ..., xN]
是您输入的数字序列,[(1 = l1, r1), (l2, r2), ..., (lM, rM = N)]
是1到N之间的索引对,用于描述(start, end)
窗口,使所有这些窗口一起满足您的约束并覆盖序列中的所有数字。现在删除xN
。显然,[x1, ..., xN]
的旧封面可以转换为[(1 = l1, r1), ..., (lM, N - 1)]
的新封面[x1, ..., x{N-1}]
,并且最多可以覆盖旧封面的窗口(或更少)。
(归纳)现在对N
进行归纳,以显示贪婪的"尽可能多地从最后 - 列表" - 算法是最佳的。
对于[x1]
,贪婪算法会找到封面[(1, 1)]
,这显然是最优的。
假设贪婪算法找到所有K <{1}}的最佳覆盖率。 N.让[x1, ..., xK]
成为M
和xN - xM <= maxWindowWidth
的最小索引。让N - M <= maxElemsPerWindow
成为涵盖Z
所需的最佳窗口数。如果我们选择[x1, ..., x{M - 1}]
作为任何(M', N)
的最后一个窗口,那么通过(remark-1),M' > M
的解决方案Z'
将等于或低于[x1, ..., x{M'}]
},即Z
,我们总共需要Z' >= Z
个窗口。由于贪心算法总是会删除尽可能多的元素,因此它会选择(Z' + 1) >= (Z + 1)
作为最后一个窗口,最后总共有(M, N)
个窗口,其中(Q + 1)
是窗口数贪心算法将用于覆盖Q
。但是通过归纳假设[x1, ..., x{M-1}]
,因此贪婪算法需要Q = Z
窗口,这等于或优于任何其他解决方案Z + 1
。
因此,贪婪算法是最佳的。
这是Scala中的草图:
Z' + 1