我正在尝试解决算法问题,这需要我根据其素因子的词典顺序对大小为N(N <= 1e6)的数字列表进行排序。列表中的每个数字都在[2,1e6]中。
Link问题。
例如,
2 3 4 5 6
将排序为:
2 4 6 3 5
他们的主要因素如下所示:
2 = 2
3 = 3
4 = 2 * 2
5 = 5
6 = 2 * 3
我的尝试:
我可以通过对每个数字使用O(logn)素因子化方法并将其存储到1e6 * 21 2d数组中来为此设计正确的解决方案,因为所有数字&lt; = 1e6最多可以有20个自2 ^ 20以来的主要因素1E6。
此后,我使用这些素因子的词汇顺序对每个数字进行排序。
我的程序能够在2秒的时间限制内运行,但使用的内存太多(内存限制为32mb)。
有人可以告诉我更好的方法来解决这个问题吗?
P.S。这个问题被标记为“深度优先搜索”,但无论如何我都看不出它是如何工作的。
答案 0 :(得分:4)
这对我来说听起来像是一个分区问题。第一步是对数组进行分区,使得除以2的数字首先出现。然后将那个组除以第二次除以2的那些。递归,直到你有一个空的子组。现在再次使用除数为3.继续列出素数列表,直到达到sqrt(1e6)或者您已找到每个数字的所有除数。
答案 1 :(得分:0)
由于您已经处于时间限制之内,因此您只需要一种更有效的方法来存储每个数字的所有素数因子,以便您可以轻松查找它们。您可以使用2级查找表执行此操作。
在一个表格中,存储数字时最多存储1e3(1000)。这将需要1e3 x 10 2d阵列(1000 x 10 x 4 = 10000字节)。
要存储最多1e6的数字的所有素因子,您需要为每个存储最多3个数字(即1200万字节)。要计算3个数字,请从素数因子列表开始,然后将它们相乘,直到不能超过1000而将其相乘。将其存储在第一个条目中,然后对余数进行相同处理并存储在第二个数字,如果剩下任何一个,只需将它放在第三个位置(你永远不需要超过3个 - 如果你有4个就意味着最后两个相乘将超过1000,这意味着第一个乘以一起的2将<&lt; 1000,在这种情况下它们不会被单独存储)。如果列表中存在超过1000的素因子,则只需要2,因为所有其他因子将乘以&lt; 1000。
要检索条目的素数因子的原始列表,请取三个数字中的每一个(将是素数或复数1000或更少或素数> 1000),如果它们低于1000,则查找其中的主要因子小表,如果不按原样,你可以重建列表。
例如存储515130(2 * 3 * 5 * 7 * 11 * 223)
1st number: 210 (2*3*5*7) can't multiply by 11 without going over 1000
2nd number: 11 (prime) can't multiply by 223 without going over
3rd number: 223
667023(3 * 7 * 23 * 1381)
1st: 438 (3*7*23)
2nd: 1381 (prime)
即使素数因子列表未排序,这也会有效。
答案 2 :(得分:0)
实际上,对我的算法进行了简单的修改就可以了。我没有存储每个整数的素数分解,而是利用了我已经拥有的东西,这是一种在O(logn)中工作的素数分解方法。我创建了一个自定义排序方法,使用分解方法对两个整数进行分解,同时比较它们的素因子。因此,时间复杂度保持不变,并且不需要存储任何整数的素数因子分解。
对于那些想知道这种快速因子分解方法是如何工作的人来说,这里是link(参见使用最低除数的方法)。
对于面临同样问题的未来读者,这是我接受的代码:
#include<cstdio>
#include<algorithm>
#define FACTOR_LIM (int) 1e6+2 // used by preFactor(n). Defined as <= n <= 1e8
using namespace std;
int lowestDiv[FACTOR_LIM+1], a[FACTOR_LIM], n;
void preFactor(int n) {
int root = 2;
for(int i = 2; i*i <= n; i++) {
if(lowestDiv[i]) continue;
root = lowestDiv[i] = i;
for(int j = i*i; j <= n; j+=i) {
lowestDiv[j] = (lowestDiv[j]) ? lowestDiv[j] : i;
}
}
for(int i = root; i <= n; i++) {
if(!lowestDiv[i]) {
lowestDiv[i] = i;
}
}
}
bool cmp(const int i, const int j) {
int x = i, y = j;
while (x != y) {
int p = lowestDiv[x];
int q = lowestDiv[y];
if (p != q) return p < q;
x /= p;
y /= q;
}
return false;
}
int main() {
preFactor(FACTOR_LIM-1);
scanf("%d",&n);
for(int i = 0; i < n; i++) {
scanf("%d",&a[i]);
}
sort(a,a+n,cmp);
for(int i = 0; i < n; i++) {
printf("%d\n",a[i]);
}
return 0;
}