最近,我试图解决Problem 23 of Project Euler。为此,我首先创建一个名为abundants
的所有大量数字的列表。
接下来,我遍历此列表并构建另一个列表,其中列出了大于某个限制的所有大量数字。现在我发现了一些奇怪的事我使用嵌套循环在列表上迭代两次。但是如果我使用数组存储总和需要几秒钟,如果我将总和添加到ArrayList则需要几个小时。这是什么原因?我认为昂贵的操作是两个嵌套循环,但似乎昂贵的操作是ArrayList #add。任何暗示为什么会这样?
这里是数组的代码:
for (int i = 0; i < abundants.size(); i++) {
for (int j = 0; j < abundants.size(); j++) {
int tot = abundants.get(i) + abundants.get(j);
if (tot <= limit)
isSum[tot] = true;
}
}
}
这里是ArrayList的代码:
ArrayList<Integer> sums = new ArrayList<Integer>();
for (int i = 0; i < abundants.size(); i++) {
for (int j = 0; j < abundants.size(); j++) {
int s = abundants.get(i) + abundants.get(j);
if (!sums.contains(s) && s < limit) {
sums.add(s);
}
}
}
答案 0 :(得分:17)
您的ArrayList实现是O(n ^ 3)而另一个是O(n ^ 2):sums.contains(...)
必须遍历内循环的每次迭代的整个sums
列表。
答案 1 :(得分:6)
我认为你的问题在于ArrayList#contains
,它必须遍历整个列表,从而将你的复杂性提高到O(n ^ 3),而不是程序的O(n ^ 2)# 1。
答案 2 :(得分:3)
您的代码不相同,.contains()
比使用原始数组的代码贵。每次调用.contains()
遍历整个数组时,不要在基于原始数组的版本中执行此操作。
答案 3 :(得分:2)
因为int
可能比Integer
快得多。
尝试在第一种情况下使用Integer[]
或在第二种情况下使用TIntArrayList
进行比较。
答案 4 :(得分:-1)
如果您知道(最大)元素数,请尝试使用给定大小初始化Array列表:
ArrayList<Integer> sums = new ArrayList<Integer>(abundants.size() * abundants.size());
由于不需要调整ArrayList的大小,这将提高速度。