这是适用于任意类型的算法,而不仅仅是两个类型:
- 将一个类型(例如A、B、C等)称为T。
- 将类型T的项目数量称为N(T)。
伪代码算法:
var size = 0;
for_each (T)
size += N(T);
var output = array(size);
var gapsRemaining = size;
for_each (T)
{
var itemsRemaining = N(T);
var i = 0;
var limit = itemsRemaining / gapsRemaining;
while (itemsRemaining > 0)
{
if (itemsRemaining / (gapsRemaining - i) >= limit)
{ output[{i}th_gap] = next_item_of_type(T)
gapsRemaining--;
itemsRemaining--;
}
else
i++;
}
}
{i}th_gap是从0开始的,就像数组索引一样。
如果您能够在常数时间内计算出{i}th_gap(可以通过使用另一个计数器来完成),则该算法为线性时间,即O(size*numTypes)。
对于您的示例,它会输出 a b a b a a b a
。
编辑
重新思考:如果您只维护每种类型的计数,则不需要那么复杂。
工作中的 JS 代码 (http://js.do/code/96801)
var numItems = [5,3]; // for AAAAABBB
var numItems = [6,3,5]; // for AAAAAABBBCCCCC
var totalNumItems = 0;
for (i=0; i<numItems.length; i++)
totalNumItems += numItems[i];
var limits = [];
for (i=0; i<numItems.length; i++)
limits[i] = numItems[i] / totalNumItems;
var numGaps = totalNumItems;
var output = [];
for (i=0; i<totalNumItems; i++)
{ var bestValue = 0;
var bestType;
for (j=0; j<numItems.length; j++)
{ var value = numItems[j] / numGaps - limits[j];
if (value >= bestValue)
{ bestValue = value;
bestType = j;
} }
output[i] = bestType;
numItems[bestType]
numGaps
}
for (i=0; i<totalNumItems; i++)
document.writeln(output[i]);
document.writeln("<br>");
但正如@Jim所说,它的时间复杂度为O(n * k),其中n是
totalNumItems
,k是
numItems.length
。因此,他的O(n log k)解决方案具有更好的复杂性。
编辑2
微调以更好地处理关系,因此更喜欢常见项目。之前代码输出[10,1,1]的结果为caaabaaaaaaa
,现在是abaaaaacaaaa
。
http://js.do/code/96848
var numItems = [10,1,1];
var totalNumItems = 0;
for (i=0; i<numItems.length; i++)
totalNumItems += numItems[i];
var limits = [];
for (i=0; i<numItems.length; i++)
limits[i] = numItems[i] / totalNumItems;
var numGaps = totalNumItems;
var output = [];
for (i=0; i<totalNumItems; i++)
{ var bestValue = 0;
var bestNumItems = 0;
var bestType;
for (j=0; j<numItems.length; j++)
{ var value = numItems[j] / numGaps - limits[j];
if (value >= bestValue && numItems[j] > bestNumItems)
{ bestValue = value;
bestNumItems = numItems[j];
bestType = j;
} }
output[i] = bestType;
numItems[bestType]
numGaps
}
for (i=0; i<totalNumItems; i++)
document.writeln(output[i]);
document.writeln("<br>");