Algorithm 有效地获取排序列表的排序和

Algorithm 有效地获取排序列表的排序和,algorithm,language-agnostic,Algorithm,Language Agnostic,你有一个升序的数字列表,你能想到的最有效的算法是什么来获得该列表中每两个数字总和的升序列表。结果列表中的重复项是不相关的,如果愿意,可以删除或避免它们 说清楚,我对算法感兴趣。请随意使用您喜欢的任何语言和范例发布代码。如果您正在寻找一个真正的语言不可知解决方案,那么我认为您将非常失望,因为您将被for循环和一些条件所困扰。但是,如果你将它开放给函数式语言或函数式语言功能(我在看你LINQ),那么我的同事们可以在这页上用Ruby、Lisp、Erlang和其他语言编写精美的示例。我能想到的最好办法是

你有一个升序的数字列表,你能想到的最有效的算法是什么来获得该列表中每两个数字总和的升序列表。结果列表中的重复项是不相关的,如果愿意,可以删除或避免它们


说清楚,我对算法感兴趣。请随意使用您喜欢的任何语言和范例发布代码。

如果您正在寻找一个真正的语言不可知解决方案,那么我认为您将非常失望,因为您将被for循环和一些条件所困扰。但是,如果你将它开放给函数式语言或函数式语言功能(我在看你LINQ),那么我的同事们可以在这页上用Ruby、Lisp、Erlang和其他语言编写精美的示例。

我能想到的最好办法是生成每对的和矩阵,然后将行合并在一起,a-la合并排序。我觉得我错过了一些简单的洞见,这些洞见将揭示一个更有效的解决方案

我的算法,在Haskell中:

matrixOfSums list = [[a+b | b <- list, b >= a] | a <- list]

sortedSums = foldl merge [] matrixOfSums

--A normal merge, save that we remove duplicates
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = case compare x y of
    LT -> x:(merge xs (y:ys))
    EQ -> x:(merge xs (dropWhile (==x) ys))
    GT -> y:(merge (x:xs) ys)

但是,如果您知道要使用所有的求和,并且提前获取其中的一些并没有好处,那么使用“
foldl merge[]
”,因为它更快。

我想我会分步骤对其进行伪编码并解释我的逻辑,以便更好的程序员可以在必要时戳破我的逻辑

在第一步中,我们从长度为n的数字列表开始。对于每一个数字,我们需要创建一个长度为n-1的列表,因为我们并没有向其自身添加一个数字。到最后,我们有一个大约n个排序列表的列表,这些列表是在O(n^2)时间内生成的

在步骤2中,由于列表是按设计排序的(在已排序列表中的每个元素中添加一个数字,列表仍将被排序),因此我们可以简单地通过将每个列表合并在一起而不是对整个批次进行合并排序来进行合并排序。最后,这需要O(n^2)个时间

然后,合并方法将是正常的合并步骤,并进行检查以确保没有重复的和。我不会写出来,因为任何人都可以查

这就是我的解决方案。整个算法是O(n^2)次。请随时指出任何错误或改进。

在SQL中:

create table numbers(n int not null)
insert into numbers(n) values(1),(1), (2), (2), (3), (4)


select distinct num1.n+num2.n sum2n
from numbers num1
inner join numbers num2 
    on num1.n<>num2.n
order by sum2n
创建表编号(n int非空)
在数字(n)中插入值(1)、(1)、(2)、(2)、(3)、(4)
选择不同的num1.n+num2.n sum2n
从数字num1
内连接数num2
关于num1.nnum2.n
sum2n订购
林克:

List num=新列表{1,1,2,2,3,4};
var uNum=num.Distinct().ToList();
var总和=(来自uNum中的num1)
来自联合国大学num2
其中num1!=num2
选择num1+num2).Distinct();
foreach(var s的总和)
{
控制台。写入线(s);
}

在python中,使用

allSums = set(a+b for a in X for b in X)
allSums = sorted(allSums)
迭代的成本是
n^2
(可能是集合的额外日志因子?),排序的成本是s*log,其中s是集合的大小

集合的大小可以大到
n*(n-1)/2
,例如,如果
X=[1,2,4,…,2^n]
。因此,如果要生成此列表,在最坏的情况下至少需要
n^2/2
,因为这是输出的大小

但是,如果您想选择结果的前k个元素,您可以使用Frederickson和Johnson的排序
X+Y
矩阵选择算法,以O(kn)的形式进行选择。尽管这可能会被修改,以便通过重用计算在线生成这些元素,并为此集合获得一个高效的生成器

@多塞尔多夫,彼得
关于
(n!)
我严重怀疑deuseldorf的意思是“n阶乘”,而仅仅是“n,(非常兴奋)!”

这个问题已经困扰了我大约一天了。太棒了

无论如何,您不能轻易地摆脱它的n^2特性,但是合并可以做得稍微好一点,因为您可以绑定插入每个元素的范围

如果查看生成的所有列表,它们的形式如下:

(a[i],a[j])|j>=i

如果将其翻转90度,则会得到:


(a[i],a[j])|i从2018年开始编辑:您可能应该停止阅读此内容。(但我不能删除它,因为它已被接受。)

如果你这样写总数:

1 4  5  6  8  9
---------------
2 5  6  7  9 10
  8  9 10 12 13
    10 11 13 14
       12 14 15
          16 17
             18

你会注意到,由于M[i,j]无论你做什么,如果没有对输入值的额外限制,你都不能比O(n^2)做得更好,因为你必须迭代所有的数字对。迭代将主导排序(你可以在O(n log n)或更快中完成)。

我认为(我的haskell生锈了)这是O(n^3)因为对结果中的每件事都进行了O(n)个比较。我认为这是O(n^3),因为在步骤2中的每个阶段都有n个比较。我认为这是O(n^3),因为每个阶段都有n个潜在的“左上角”。你可以在O(n^2 log n)中实现这个算法通过在优先级队列的每一行中存储第一个未勾选的条目来节省时间,但渐进地说,这并不比只生成所有总和和排序要好。如果您有两个长度为m和n的列表,而不是一个,并且在4年后进行mOn反射,这似乎是merge sort的一个非常糟糕的版本:)这比我认为的所有其他解决方案都要复杂!O(n^2.log(n))。它也是可读性最好、最短的。是的,但是对n^2个事物进行排序需要O(n^2 log n),所以排序永远不会占主导地位。
create table numbers(n int not null)
insert into numbers(n) values(1),(1), (2), (2), (3), (4)


select distinct num1.n+num2.n sum2n
from numbers num1
inner join numbers num2 
    on num1.n<>num2.n
order by sum2n
List<int> num = new List<int>{ 1, 1, 2, 2, 3, 4};
var uNum = num.Distinct().ToList();
var sums=(from num1 in uNum
        from num2 in uNum 
        where num1!=num2
        select num1+num2).Distinct();
foreach (var s in sums)
{
    Console.WriteLine(s);
}
allSums = set(a+b for a in X for b in X)
allSums = sorted(allSums)
1 4  5  6  8  9
---------------
2 5  6  7  9 10
  8  9 10 12 13
    10 11 13 14
       12 14 15
          16 17
             18