我有一个整数数组。每个元素的值表示处理文件所花费的时间。文件的处理包括一次合并两个文件。寻找可用于处理所有文件的最短时间的算法是什么?例如。 -{3,5,9,12,14,18}。
处理时间可以计算为- 情况1)-
@Binding
所以处理的总时间为61 + 35 + 26 + 17 + 8 = 147
情况2)-
Text
这次总时间为61 + 40 + 23 + 17 + 21 = 162
在我看来,如情况1所示,连续排序数组并添加最少两个元素是最小的最佳选择。我的逻辑对吗?如果不是,那么以最佳性能实现这一目标的正确,最简单的方法是什么?
答案 0 :(得分:2)
有了排序列表后,由于您只删除了两个最小项并用一个替换,因此更有意义的是进行排序插入并将新项放置在正确的位置,而不是对整个项重新排序清单。但是,这只节省了少量时间-快了约1%。
我的方法CostOfMerge
不假定输入为List
,但如果是,则可以删除转换ToList
步骤。
public static class IEnumerableExt {
public static int CostOfMerge(this IEnumerable<int> psrc) {
var src = psrc.ToList();
src.Sort();
while (src.Count > 1) {
var sum = src[0]+src[1];
src.RemoveRange(0, 2);
var index = src.BinarySearch(sum);
if (index < 0)
index = ~index;
src.Insert(index, sum);
total += sum;
}
return total;
}
}
答案 1 :(得分:2)
正如在其他答案中已经讨论的那样,最好的策略将是始终以最小的每次迭代成本在两个项目上工作。因此,唯一剩下的问题是如何有效地每次取出两个最小的物品。
由于您要求获得最佳性能,因此我毫不客气地从NetMage中提取了该算法,并对其进行了修改,以使其在我的测试用例中可以提高大约40%的速度(感谢和NetMage的+1)。
这个想法主要是在单个阵列上就地工作。 每次迭代都会将起始索引增加1,并移动数组中的元素以为当前迭代的总和腾出空间。
public static long CostOfMerge2(this IEnumerable<int> psrc)
{
long total = 0;
var src = psrc.ToArray();
Array.Sort(src);
var i = 1;
int length = src.Length;
while (i < length)
{
var sum = src[i - 1] + src[i];
total += sum;
// find insert position for sum
var index = Array.BinarySearch(src, i + 1, length - i - 1, sum);
if (index < 0)
index = ~index;
--index;
// shift items that come before insert position one place to the left
if (i < index)
Array.Copy(src, i + 1, src, i, index - i);
src[index] = sum;
++i;
}
return total;
}
我用以下调用代码(在CostOfMerge
和CostOfMerge2
之间切换)进行了测试,并为随机种子,元素数量和初始项目的最大值设置了一些不同的值。
static void Main(string[] args)
{
var r = new Random(10);
var testcase = Enumerable.Range(0, 400000).Select(x => r.Next(1000)).ToList();
var sw = Stopwatch.StartNew();
long resultCost = testcase.CostOfMerge();
sw.Stop();
Console.WriteLine($"Cost of Merge: {resultCost}");
Console.WriteLine($"Time of Merge: {sw.Elapsed}");
Console.ReadLine();
}
显示的NetMage CostOfMerge配置的结果:
Cost of Merge: 3670570720
Time of Merge: 00:00:15.4472251
我的CostOfMerge2:
Cost of Merge: 3670570720
Time of Merge: 00:00:08.7193612
当然,详细的数字取决于硬件,并且根据负载的不同,差异可能更大或更小。
答案 2 :(得分:1)
否,这是多相合并的最小值:N
是带宽(可以同时合并的文件数),然后您希望在每一步合并最小的(N-1)个文件。但是,由于存在这个更普遍的问题,您希望尽可能长的时间延迟较大的文件-您可能希望提前一到两个步骤合并少于(N-1)个文件,这有点像消除中的“再见”比赛。您希望后面的所有步骤都包含完整的(N-1)个文件。
例如,给定N = 4和文件1, 6, 7, 8, 14, 22
:
早期合并:
[22], 14, 22
[58]
total = 80
后期合并:
[14], 8, 14, 22
[58]
total = 72
答案 3 :(得分:1)
在这里,您可以应用以下逻辑来获得所需的输出。
如果发现有帮助的.. :)
,您可以按照我的Java代码进行操作。public class MinimumSums {
private static Integer getFirstMinimum(ArrayList<Integer> list) {
Integer min = Integer.MAX_VALUE;
for(int i=0; i<list.size(); i++) {
if(list.get(i) <= min)
min = list.get(i);
}
return min;
}
private static Integer getSecondMinimum(ArrayList<Integer> list, Integer firstItem) {
Integer min = Integer.MAX_VALUE;
for(int i=0; i<list.size(); i++) {
if(list.get(i) <= min && list.get(i)> firstItem)
min = list.get(i);
}
return min;
}
public static void main(String[] args) {
Integer[] processes = {5, 9, 3, 14, 12, 18};
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList<Integer> temp = new ArrayList<Integer>();
list.addAll(Arrays.asList(processes));
while(list.size()!= 1) {
Integer firstMin = getFirstMinimum(list); // getting first min value
Integer secondMin = getSecondMinimum(list, firstMin); // getting second min
list.remove(firstMin);
list.remove(secondMin);
list.add(firstMin+secondMin);
temp.add(firstMin + secondMin);
}
System.out.println(temp); // prints all the minimum pairs..
System.out.println(list.get(0)); // prints the output
}
}