我在 Codewars 中练习解决问题。坚持以下内容:有一个数字,例如,42。它的除数是数字1, 2, 3, 6, 7, 14, 21, 42。所有除数的平方和为2500。而2500又是整数 的平方50。
因此,我们将一系列数字从m到提供给函数的输入n。有必要编写一个算法,在从m到的区间内n,找到所有满足上述条件的整数 - 它们的除数的平方和本身必须是整数的平方。
该函数返回一个数组数组——例如,在1到250的范围内,三个数字满足条件,输出将是一个数组[[1, 1], [42, 2500], [246, 84100]],其中第一个数字是满足条件的数字,第二个是其除数的平方和。
如果有的话,问题本身:https ://www.codewars.com/kata/55aa075506463dac6600010d
我写了一个完全可行的算法。但是,如果 Codewars 认为算法效率低下,它有时会拒绝解决方案。为了提高算法的效率,我对它做了两处修改:
- 该数字没有大于该数字一半的整数除数,因此
for当我们通过该数字的一半时退出循环 - 如果这个数是奇数,那么它的所有除数也是奇数,所以当在 for 循环中检查奇数时,我们移动到第 2 步:
1,3,5等等。
无论如何,我的 Codewars 算法拒绝。你能告诉我如何提高这个算法的速度吗?也许我选择了错误的解决方案?第二个问题源于我的优化。我塞了很多不同的奇偶校验,检查数字是否大于被检查数字的一半。它值多少钱,也许这些检查只会减慢代码的速度,并且不会使程序免于不必要的计算?
编码:
fun listSquared(m: Long, n: Long): String {
var finalArray = mutableListOf<List<Long>>()
var sum: Long
for (i in m..n){
sum = 0
if (i % 2 == 0L){
for (j in 1..i){
if (i % j == 0L){
sum += j.toDouble().pow(2).toLong()
if (i/j < 2) break // у числа не бывает делителя больше, чем половина этого числа
}
}
} else {
for (j in 1..i step 2){ // если число нечетное, то все его делители тоже нечетные
if (i % j == 0L){
sum += j.toDouble().pow(2).toLong()
if (i/j < 2) break
}
}
}
if ((sqrt(sum.toDouble()) % 1.0) == 0.0){
finalArray.add(listOf(i, sum))
}
}
return finalArray.toString()
}
确实是的。他们只会放慢速度。毕竟要检查的数字会少于 4 次,会被 ifof 处理吞噬掉。
有两个选项不需要复杂的数学:第一个是利用一个数字的每个除数都有一对这一事实,并减少 O(sqrt(n)) 的排序。第二个是肮脏的预先计算:)