我的某些程序必须具有严格的时间限制才能完成给定的任务。
如果我是正确的,将某些循环转换为数学方程应该会减少我的程序的时间复杂度,是吗?我可以在一次操作中得到循环找到的相同结果吗?
我已经检查了很多关于这个问题的其他解决方案,遗憾的是他们都专注于解决循环本身,而不是应该采取的一般步骤将循环转换为数学方程式,我无法理解得多。
我需要能够自己转换循环,而且我无法在互联网上的任何地方找到帮助解决这个问题。参考文献将不胜感激。
例如,在某些情况下,此循环需要7秒以上:
for (int j = 0; j < N * M; j++){
S += V;
V = (A * V + B) % (10007);
}
这个也需要一秒多的时间:
for (int i = 1; i <= product; i++){
if (product % i == 0)
sum += i;
}
请注意我的问题不在于这两个循环,我需要知道如何处理任何可转换循环。答案也不仅限于方程式,任何性能提示都表示赞赏。
编辑:Here就是我的意思。
答案 0 :(得分:2)
您确实可以使用mathematical induction来推断循环等效于简单公式。您链接的问题中的循环是系列的简单总和,易于推理。但是,并非所有循环都可以简化为公式。
使用归纳法推理任何一个循环都很困难。第一个具有余数运算,使输出周期性。由于它是周期性的,因此单个归纳步骤不适用于j
的每个增量。证明循环存在一个简单的公式,更不用说找到那个公式,这超出了我的数学技能。
我认识到你的第二个循环中的情况。这是对i
是否为product
因子的测试。所以,基本上,你将所有因素加在一起。我可以直观地猜测没有简单的方法来找到一个简单的公式,因为我知道没有已知的快速算法进行整数分解(即找到整数的所有因子)。
比测试每个小于product
的数字更快的算法,但对于小数字,如int
,它还不错。
作为优化,您可以将迭代次数减少一半,因为我们知道没有比这更大的数字(除了product
本身)是一个因素。 1
始终是一个因素,因此我们可以在初始化期间添加它。更进一步,我们可以添加对因子,并且只迭代直到产品的平方根:
int sum = 1 + product;
int root = sqrt(product);
for (int i = 2; i < root; i++){
if (product % i == 0)
sum += (i + product / i);
}
// add square root separately, because it doesn't have a pair
if (root*root == product)
sum += root;
答案 1 :(得分:2)
我没有时间将解决方案完全扩展到代码中,但您会发现有用的想法。
First Loop
首先我将N*M
更改为仅N
,因为它会简化方程式的编写(然后您可以在最终的方程中替换回来找到正确的公式)。进入循环时,我还假设S
等于0
。我还将在Z / 10007Z领域工作(10007是素数)
for (int j = 0; j < N; j++){
S += V;
V = (A * V + B) % (10007);
}
基本上,您有一系列数字v_i
和一个和S_i
定义如下:
v_0 = ? // not important in the following equations
S_0 = 0
v_{i+1} = (A*v_i+B)
S_{i+1} = S_i + v_{i}
您可以将v_i
的重复公式重写为矩阵运算:
|v_{i+1}| | A B | |v_i|
| | = | | | |
| 1| | 0 1 | | 1|
让我们调用M
矩阵。您现在可以通过以下公式轻松计算任何值v_i
:
|v_i| i |v_0|
| | = M | |
| 1| | 1|
然后通过将i
从0加到N
得到:
|S| / N i \ |v_0|
| | = |SUM M | | |
|1| \i=0 / | 1|
让我们调用矩阵M的幂的总和:Q
您可以轻松证明M
的第i个力量是:
i | A^i B(A^i+A^(i-1)+...+1) |
M = | |
| 0 1 |
原来是:
i | A^i B(1-A^(i+1))/(1-A) |
M = | |
| 0 1 |
(见:https://en.wikipedia.org/wiki/Geometric_series#Sum)
因此我们可以将Q
重写为:
| (1-A^(N+1))/(1-A) B*SUM(i=1,N, B(1-A^(i+1))/(1-A) ) |
Q = | |
| 0 1 |
最终我们得到:
1 | 1-A^(N+1) B*( N - (1-A^(N+1))/(1-A) ) |
Q = --- | |
1-A | 0 1 |
您可以在A^(N+1)
中轻松计算O(log(N))
。
计算1/(1-A)
是根据费马的小定理计算(1-A)^(10007-1-1)
完成的。
如果事先知道A
,您甚至可以预先计算它。
显然,一切都是在数字模数10007的领域完成的,如前所述。
第二次循环
基本上你计算一个数的除数。我不知道有什么更好的方法。 但是如果您必须为许多连续的数字执行此操作,则可能会进行优化。