给定一个
n
元素数组,数组的k分区是将数组拆分为k
个连续的子数组,以使子数组的最大值不增加。即max(subarray1) >= max(subarray2) >= ... >= max(subarrayK)
。如何多种方式可以将数组划分为有效的分区,如前面提到的那样?
注意:
k
未作为输入或任何内容提供,我mereley用它来说明一般情况。分区的大小可以是1
到n
,我们只需找到所有有效的分区。
例如,数组[3,2,1]可以用4种方式分区,你可以在下面看到它们:
有效分区:[3,2,1]; [3,[2,1]]; [[3,2],1]; [[3],[2],[1]]。
我发现了与线性分区相关的类似问题,但我无法找到一种方法来适应这个问题。我很确定这是动态编程,但我还没有能够正确识别 如何使用递归关系对问题建模。 你会如何解决这个问题?
答案 0 :(得分:0)
如果输入元素至少与后面的所有元素一样大,则调用 tail-max 的输入元素。例如,在以下输入中:
5 9 3 3 1 2
以下元素是尾部最大值:
5 9 3 3 1 2
^ ^ ^ ^
在有效分区中,每个子数组必须包含子数组起始位置或之后的下一个尾部最大值;否则,下一个尾部最大值将是某个后续子阵列的最大值,并且将违反非增加子阵列最大值的条件。
另一方面,如果每个子数组在子数组的起始位置或之后包含下一个尾部最大值,则该分区必须有效,因为尾部最大值的定义确保后续子数组的最大值不能是大。
如果我们识别数组的尾部最大值,例如
1 1 9 2 1 6 5 1
. . X . . X X X
其中X表示尾部最大值和。意思是没有,那么我们就不能在第一个尾部最大值之前放置任何子阵列边界,因为如果我们这样做,第一个子阵列将不包含尾部最大值。我们最多可以在一个尾部最大值和下一个之间放置一个子阵列边界;如果我们放置更多,我们得到一个不包含尾部最大值的子阵列。最后一个tail-max必须是输入的最后一个元素,因此我们不能在最后一个tail-max之后放置一个子数组边界。
如果尾部最大值与下一个之间存在m
个非尾部最大元素,则会为我们提供m+2
个选项:m+1
放置数组边界的位置,或者我们可以选择不在这些元素之间放置边界。这些因素是乘法的。
我们可以从输入的末尾到开头进行一次传递,确定尾部最大值之间的间隙长度,并将适当的因子相乘以在O(n)
时间内解决问题:
def partitions(array):
tailmax = None
factor = 1
result = 1
for i in reversed(array):
if tailmax is None:
tailmax = i
continue
factor += 1
if i >= tailmax:
# i is a new tail-max.
# Multiply the result by a factor indicating how many options we
# have for placing a boundary between i and the old tail-max.
tailmax = i
result *= factor
factor = 1
return result
答案 1 :(得分:-1)
更新:抱歉,我误解了这个问题。在这种情况下,将数组拆分为子数组,其中每个尾部是数组中的最大元素,然后它将在狭窄的情况下工作。例如[2 4 5 9 6 8 3 1]将首先分为[[2 4 5 9] 6 8 9 3 1]。然后我们可以自由选择范围0 - 5来决定是否包括以下内容。您可以使用数组记录DP的结果。我们的目标是res[0]
。我们在上面的示例中已经有res[0] = res[5] + res[6] + res[7] + res[8] + res[9] + res[10]
,res [10] = 1
def getnum(array):
res = [-1 for x in range(len(array))]
res[0] = valueAt(array, res, 0)
return res[0]
def valueAt(array, res, i):
m = array[i]
idx = i
for index in range(i, len(array), 1):
if array[index] > m:
idx = index
m = array[index]
value = 1;
for index in range(idx + 1, len(array), 1):
if res[index] == -1:
res[index] = valueAt(array, res, index)
value = value + res[index]
return value;
比上面的答案更耗费时间。 DP总是花费很多。
旧答案:如果允许数组中没有重复的元素,则以下方式可行:
请注意,如果没有重复,子数组的数量不取决于元素的值。如果数组中有n个元素,我们可以注意数字为N(n)
。
最大元素必须位于第一个子数组中,其他元素可以存在于第一个子数组中或不存在于第一个子数组中。取决于它们是否在第一个子数组中,其余元素的分区数会有所不同。
所以,
N(n) = C(n-1, 1)N(n-1) + C(n-1, 2)N(n-2) + ... + C(n-1, n-1)N(0)
其中C(n,k)表示:
然后它可以由DP解决。
希望这有帮助