我想计算一个列表“十字路口”。问题是:
L1 = [1, 0, 2, 3, 1 , 3, 0, 5]
L2 = [3, 5]
然后结果将是
L3 = [0, 0, 0, 1, 0, 1, 0, 1]
然后我将在一个字节中转换此结果。在这种情况下,将以十进制格式为21。
我想在delphi中制作,我需要这样做有效。有没有办法比O(m * n)更好地解决这个问题?
答案 0 :(得分:3)
这是一个应该做你想要的功能。我将L2
定义为集合而不是数组,因为您说所有值都适合Byte
。它的复杂性是O(n);检查集成员资格在恒定时间内运行。但由于结果需要适合一个字节,L1
的长度必须绑定为8,因此该函数的复杂度实际上是O(1)。
function ArrayMembersInSet(const L1: array of Byte; const L2: set of Byte): Byte;
var
i: Integer;
b: Byte;
begin
Assert(Length(L1) <= 8,
'List is to long to fit in result');
Result := 0;
for i := 0 to High(L1) do begin
b := L1[i];
if b in L2 then
Result := Result or (1 shl (7 - i));
end;
end;
答案 1 :(得分:1)
Rob的回答将适用于这个具体案例。对于需要比较两个列表的更一般情况,如果两个列表都已排序,则可以在O(m + n)时间内完成。 (或者如果你必须先对它们进行排序,则为O(n log n)时间,但这仍然比O(m * n)快很多。)
基本列表比较算法如下所示:
procedure ListCompare(list1, list2: TWhateverList; [Add extra params here]);
var
i, j: integer;
begin
i := 0;
j := 0;
while (i < list1.Count) and (j < list2.Count) do
begin
if list1[i] < list2[j] then
begin
//handle this appropriately
inc(i);
end
else if list1[i] > list2[j] then
begin
//handle this appropriately
inc(j);
end
else //both elements are equal
begin
//handle this appropriately
inc(i);
inc(j);
end;
end;
//optional cleanup, if needed:
while (i < list1.Count) do
begin
//handle this appropriately
inc(i);
end;
while (j < list2.Count) do
begin
//handle this appropriately
inc(j);
end;
end;
这可以针对一大堆任务进行自定义,包括列表交集,通过更改“适当处理”这些位置,并且保证不会运行比两个列表放在一起的更多步骤。对于列表交集,使用等于大小写将值添加到某个输出,而另外两个除了推进计数器之外什么也不做,您可以不进行可选的清理。
使用这种算法的一种方法是将顶部的额外参数设置为函数指针,并传入将处理适当情况的例程,或者不执行任何操作。 (如果你走这条路,请确保在调用它们之前检查nil!)这样你只需要编写一次基本代码。
答案 2 :(得分:0)
无论您需要访问每个列表中的每个元素,比较值。嵌套循环可以在O(n ^ 2)中完成此操作,转换应该只是本地工作。
编辑:我注意到你想要比O(n * m)更好的运行时间。