Algorithm 有没有快速的方法来生成按乘积排序的笛卡尔坐标对?

Algorithm 有没有快速的方法来生成按乘积排序的笛卡尔坐标对?,algorithm,language-agnostic,Algorithm,Language Agnostic,我想在一个有界的正方形内生成笛卡尔坐标对,按其乘积降序排列。例如,对于大小为3的正方形,坐标为: (3,3), (3,2), (2,3), (2,2), (3,1), (1,3), (2,1), (1,2), (1,1) 有没有办法快速生成此列表?例如,一个将整数映射到第n个坐标的常数时间函数?也许您可以详细说明您的具体需求,即您希望生成的速度有多快,以及更改正方形边界的速度有多快 这个问题类似于在乘法表中生成不同的数字(Paul Erdos研究了乘法表的基数,已知精确计算的最快算法是O(n^

我想在一个有界的正方形内生成笛卡尔坐标对,按其乘积降序排列。例如,对于大小为3的正方形,坐标为:

(3,3), (3,2), (2,3), (2,2), (3,1), (1,3), (2,1), (1,2), (1,1)

有没有办法快速生成此列表?例如,一个将整数映射到第n个坐标的常数时间函数?

也许您可以详细说明您的具体需求,即您希望生成的速度有多快,以及更改正方形边界的速度有多快

这个问题类似于在乘法表中生成不同的数字(Paul Erdos研究了乘法表的基数,已知精确计算的最快算法是O(n^2))

一种考虑列表生成部分的方法(假设你不会列出数十亿个坐标),就是快速降序部分代码<> **j//>s按降序排序并排序它们。为了使散列精确,我们将其扩展到所选范围[n,k]以下,直到对于某些

l
n*l
低于
k*k
。例如,对于从(10,10)到(7,7)的坐标范围,我们将散列扩展到(5,5),以便包含大于(7,7)的(10,5)

JavaScript代码:

函数f(n,k){
var l=k,k2=k*k;
而(n*l>k2){
l--;
}
控制台日志(“下限:+l”);
var h={},h2=[];
对于(变量i=n;i>l;i--){
对于(var j=i;j>l;j--){
var m=i*j;
如果(h[m])h[m]=h[m].concat([i,j]);
否则{
h[m]=[i,j];
h2.推力(m);
}
}
}
h2.sort(函数(a,b){返回b-a});
var i=0;
而(h2[i]>=k2){
log(h[h2[i++]);
}
}
输出:

f(10,6)

low bound: 3

(10,10) 
(10,9) 
(9,9) 
(10,8)
...
(10,4), (8,5)
(9,4), (6,6)
更多输出:

f(1000000,999995)

low bound: 999990

(1000000,1000000) 
(1000000,999999) 
(999999,999999)
(1000000,999998) 
(999999,999998) 
(1000000,999997) 
(999998,999998) 
(999999,999997) 
(1000000,999996) 
(999998,999997)
(999999,999996) 
(1000000,999995) 
(999997,999997)
(999998,999996)
(999999,999995) 
(1000000,999994)
(999997,999996) 
(999998,999995) 
(999999,999994) 
(1000000,999993) 
(999996,999996)
(999997,999995) 
(999998,999994) 
(999999,999993) 
(1000000,999992) 
(999996,999995) 
(999997,999994) 
(999998,999993) 
(999999,999992) 
(1000000,999991) 
(999995,999995)

我还没有测试过这个想法。只需从右下角到左上角去掉对角线,就可以按照大致正确的顺序快速生成所有坐标的列表,就像。这将为您提供一个近乎有序的列表


有一些排序方法可以利用这一点为您提供更快的排序。请参阅以进行讨论。您可以尝试不同的排序算法,看看哪些算法最适合您的数据。

您的枚举自然应该从右上角到左下角进行

将边界保持为优先级队列。开始时,右上角是边界中唯一的一个条目

在每一步中,从PQ中弹出max元素并将其三个子元素(西部、南部和西南部)插入队列中,而不创建重复项(可能使用实际数组来支持队列,但这意味着额外的空间…嗯,这些短元素中只有
n
(例如,垂直)数组,每个数组不超过几个元素,它们从不向上增长/移动,只向下移动)

队列的长度是O(n)–想想,–

并且会产生n2个结果,因此总体复杂性取决于队列实现的效率。如果是对数的,它将是O(n2 logn),如果是线性的(使用哈希表,因为我们知道所涉及的值的范围),O(n2),总的来说;但它将是在线的,每生产一对都是-O(1)…O(logn)

如果精度允许(对于您的范围,它看起来是允许的),则预先计算坐标的对数,并按
log(x)+log(y)
而不是
x*y
对坐标对进行排序,用O(n2)乘法换n个对数和O(n2)加法


编辑:查看另一个非常类似的算法的实际Haskell代码;它还包含额外的提示,如何将其速度提高2倍(
xy==yx
),因此只需处理正方形的三角形一半——这也将使所需空间减半。看起来没有必要将
SW
子级添加到优先级队列中,只要
s
W
就足够了

前三对看起来很明显,第四对并不难。把它拼出来,试着概括一下。你为什么遗漏了(3,1)和(1,3)?没关系。这些序列非常复杂。你使用的N的值(如果平方是NxN)大致是多少数量级?有点大,5~10(所以,数字高达100000000)。我设法找到了一个解决方案,它返回块,这样块中的所有对都比下一个块中的任何对大,但块中的顺序不保证。我通过得到
x*y=k
行的两个常数之间的项来实现这一点。因为这太愚蠢了。修复了。快速散列一组
i*j
s-如O(N²)?@greybeard部分,而不是全部
i*j
。无论如何,对部分进行排序似乎比从原始问题:
一个接一个地降序要快得多…:),也就是说,一个将整数映射到第n个坐标的常数时间函数。
。我认为没有一个可以,这可能就是为什么答案很慢的原因。@greybeard,问题以“我想在一个有界正方形内生成笛卡尔坐标对,按其乘积降序排列。“也就是说,它确实谈到了生成“对”,复数。--OP接着说“有没有办法快速生成此列表”,再次谈到生成整个列表。因此,我对它进行了阅读。足够接近,可以将此问题作为一个子问题来结束:-/鉴于此(我无法辨别)(尝试开始,并在适当的时候找到解决方案),可能值得重新询问或(包括指针)上问题的适当重新措辞变体。