假设我有一个循环的数字列表(最后一个元素被认为与第一个元素相邻):
10 10 10 10 9 8 10 8 19
我希望在最多给定大小的集合中分发它们,以便每个集合包含连续的数字。
对于此示例,请说我的设置大小为48。
我可以直截了当地{10 10 10 10}, {9 8 10 8}, {19}
因此产生3套。
但我也可以做{10 10 10 9 8}, {10 8 19 10}
- 2套(记住清单是循环的)。
如何计算可包含所有数字的最小数量?优选地,O(n)关于计算和存储。
答案 0 :(得分:1)
您希望将数据划分为序列,以使每个序列的总数不超过某个常量。
选择第一个序列的起始点,例如,0。贪图地向此序列添加元素,然后添加到下一个序列,依此类推,直到消耗完所有数据。这是一个可能的分区。
要创建另一个分区,请从位置1开始。再次贪婪地使用所有数据。这是另一个可能的分区。然后从位置2开始做同样的事情,依此类推。一旦使用了属于第一个分区的第一个序列的每个起始点,就可以停止。任何进一步的起点只会产生一个与之前的分区相同的分区。
data = [10, 10, 10, 10, 9, 8, 10, 8, 19]
max_size = 48
n = len(data)
# make a partition starting from position 0
bounds = [0]
total = 0
for pos in range(n):
x = data[pos]
if total + x <= max_size:
total += x
else:
bounds.append(pos)
total = x
# the first partition ends here
limit = bounds[1]
best_bounds = bounds
# make all other possible partitions
for start in range(1, limit):
bounds = [start]
total = 0
pos = start
while True:
x = data[pos]
if total + x <= max_size:
total += x
else:
bounds.append(pos)
total = x
pos = (pos + 1) % n
if pos == start:
break
if len(bounds) < len(best_bounds):
best_bounds = bounds
# assemble and display the best partition
partition = []
sequence = []
start = best_bounds[0]
index = 1
pos = start
while True:
if pos == best_bounds[index]:
partition.append(sequence)
if pos == start:
break
sequence = []
index = (index+1)%len(best_bounds)
sequence.append(data[pos])
pos = (pos + 1) % n
print('partition of size %d: %s' % (len(partition), partition))
答案 1 :(得分:1)
这是线性时间。
所以你有一个数组,比如[10 10 10 10 9 8 10 8 19]
和一个像48
这样的界限。
第一步是找出总和低于界限的所有连续元素的最大组。这样做我们将填充另一个数组,如果你有一个从这里开始,那么下一个连续组必须从这个位置开始。
要做到这一点,我们会跟踪我们从哪里开始,去哪里,以及我们当前范围的总和。每当我们的总数低于我们的范围时,我们就会推进结束并增加总数。每当我们的总数高于界限时,我们将start
的下一个范围的开头标记为end
,提前start
,并从total
中减去该元素。我们继续,直到我们发现一切都进入一个范围(在这种情况下,你的最终答案是1)或start
包裹。
在这个阶段,我们总是推进一个指针,我们最多可以提前end
次2n
次(超过我们有一个包裹和停止的时间)并结束n
次(直到它包装)所以这是O(n)
到目前为止。
现在我们可以从最后向后构建连接问题的答案,&#34;在我回合之前有多少组?&#34;和&#34;我在哪里与这么多团体进行交流?&#34;对于最后包装的那些位置,答案是1,无论你的next_start
是什么。对于早期的答案,答案是&#34;比我的next_start
&#34;和&#34;到next_start
跳到. This is another
n operations for
O(n)`的地方。
现在我们可以扫描数组中的候选起始位置。候选起始位置是包裹自身或更远的位置。你得到的分区的大小是&#34;直到我回合的组数#34;您的答案是具有最小组数的候选起始位置。这又是O(n)
步骤并为您提供答案。
因此,您的最长运行时间为O(n)
。