2520是可以除以1至10中的每个数字而没有任何余数的最小数字。 可以被1到20的所有数字整除的最小正数是多少?
适用于样本编号2520。
但不是1到20之间的数字,它不会给我任何回报,所以我的错误是什么?
function findFactor(n, max) {
var acc = 0;
for(var i = 2; i <= max; ++i) {
acc += !(n%i) ? 1 : 0;
}
return acc === max - 1 ? true : false;
}
for(var i = 2520; true; ++i) {
if(findFactor(i, 20)) {
console.log(i)
}
if(i > 1e7) console.log("Limit")
}
&#13;
答案 0 :(得分:2)
您的代码存在一些缺陷:
您永远不会退出循环for (var i = 2520; true; ++i)
。即使匹配,浏览器也会冻结并且不会记录任何内容。
您只需将i
增加1,这是多余的。增加20,因为你的答案必须能被20整除。
acc += !(n%i) ? 1 : 0;
也是多余的。如果n % i !== 0
,您不需要进一步迭代,只需返回false。
考虑到所有这些更正,您可能会遇到以下情况:
function findFactor(n, max) {
for (let i = 2; i <= max; i++) {
if (n % i !== 0) return false;
}
return true;
}
let n = 20;
//measuring performance
let start = performance.now();
for (let i = n; true; i += n) {
if (findFactor(i, n)) {
console.log(i);
break;
} else if (i > 1e10) {
console.log("Limit");
break;
}
}
console.log(`time spent: ${performance.now() - start}`);
&#13;
还有另一种方法可以计算两个以上数字的最小公倍数(LCM) - 通过迭代计算两个数字的最小公倍数:
lcm(a, b, c) = lcm(a, lcm(b, c))
两个数字can be computed as follows的最小公倍数:
lcm(a, b) = a * b / gcd(a, b)
其中gcd(a, b)
是最大的公约数。要找到它,您可以使用Euclidean algorithm
//greatest common divisor
const gcd = (a,b) => {
while (a !== 0 && b !== 0) {
if (a > b) a %= b;
else b %= a;
}
return a + b;
};
//least common multiple
const lcm = (a, b) => a * b / gcd(a, b);
const leastMultipleOfRange = n => {
if (n < 3) return n;
let acc = 2;
for (let i = 3; i <= n ; i++) {
acc = lcm(acc, i);
}
return acc;
};
let start = performance.now();
console.log(leastMultipleOfRange(20));
console.log(`time spent: ${performance.now() - start}`);
&#13;
最有可能的是,有一些更有效的方法来计算几个数字的最小公倍数,例如保罗所提到的,但我对数学的了解并不是很深刻来解释它们。
答案 1 :(得分:1)
解决此问题的更有效方法是计算least common multiple(lcm)。我们可以使用的基本思想类似于通过factorization计算lcm(虽然我们不直接使用分解)。
我们可以表示a
将b
平均分为a | b,而不是a∤b。如果两个数字没有共同因素,则它们是互质的;这也需要lcm(a, b) = a * b
,如果a
和b
是互质的。 m = lcm(a, b)
具有属性a | m和b | m,并且不存在m_<m
,使得| m_和b | m_。由于对于每个整数,存在唯一的因子分解(如fundamental theorem of arithmetic中所述),我们可以将a
,b
和m
表示为素数的乘积:
m的因式分解表明m
中没有多余的因素。它与a
和b
一样可以被整除。
多个数字的lcm可以递归地从两个数字的lcm计算:
lcm(a, b, c) = lcm(lcm(a, b), c)
这些是有效解决问题所需的基本数学工具。现在我们留下了两个问题:哪个素数在我们lcm的因子分解中具有幂> 0
,哪些值具有相应的指数?
我们可以使用以下事实确定lcm([1..n])
的因式分析中的哪些素数:让p
εP和p <= n
,然后p
显然在序列中,所以它也必须是最不常见的倍数。现在p > n
怎么样?让我们从两个值的lcm开始:a
和b
,其中a < p
和b < p
。由此我们可以得出结论p∤a和p∤b,所以p | lcm(a,b)也不能保持。一般来说,如果p∤a和p∤b,那么p∤lcm(a,b)必须成立。证明:
Assume m = lcm(a, b) and p | m
m = a * n1 = b * n2
但是因为p∤a和p∤b我们也得到了
m = a * p * n1_ = b * p * n2_
n1_ * p = n1
n2_ * p = n2
因此我们可以使用以下属性构造m_
:
m_ * p = m
a|m_
b|m_
因此,大于a
和b
的素数永远不会是lcm(a, b)
的因子。由于lcm超过两个整数的递归定义,我们可以很容易地证明,这需要n
不能成为lcm([1..n])
因子的任何素数。
因此,我们的因子分解将包含的素数都在[1..n]
范围内。例如。对于n=20
,就像项目euler中的问题一样,这将是素数[2, 3, 5, 7, 11, 13, 17, 19]
。
仍然是要解决的最后一个问题:分解中每个素数的指数。在第一步中,我们可以查看单个数字的权力:
lcm(x^e1,x^e2) = x^e2, if e1 < e2
因此,例如在我们的问题中,2的指数必须是4:
[1..20]
范围内2的最大幂为16 = 2 ^ 4。任何较小的2的幂除以16.因此对于给定的n
,我们可以将指数计算为
所以现在我们有一部分序列的lcm(素数的所有幂):
lcm(2,4,8,16, 3,9, 5, 7, 11, 13, 17, 19) =
lcm(lcm(2, 4, 8, 16), lcm(3, 9), 5, 7, 11, 13, 17, 19) =
lcm(16, 9, 5, 7, 11, 13, 17, 19) =
2^4 * 3^2 * 5^1 * 7^1 * ... * 19^1
上述等式的最后几行是由于素数和它们的能力总是彼此相互作用(见上文)。
但序列中的剩余数字呢?我们实际上并不需要它们。每个不是素数本身的数字都是素数幂的乘积(unique factorization)。所以我们假设c = p1^e1 * p2^e2
以及a = p1^f1
和b = p2^f2
,其中a
,b
和c
的范围为{{1} }}和[1..n]
和f1
是最大的。然后f2
和e1 <= f1
必须保留,否则e2 <= f2
无法保持(请记住c <= n
和f1
已经是相应的最大指数素数,例如f2
)。因此p1^(f1 + 1) > n
c | lcm(a, b)
a
,b
和c
如上所定义,可以基于lcm(a, b)
a
的因子分解得出,{ {1}}(见上文)。
嗯,这是理论部分的数字,一些实际代码的时间(以防万一你仍然读到这个:D)。至少我们现在有一些非常漂亮的代码:
b
run = function(){
document.getElementById('output_id').innerHTML = 'Calculating...'
var n = document.getElementById('input_n_id').value;
// sieve of eratosthenes, the quick and dirty way
var primes = Array((n - 1) >> 1).fill(0).map((v, i) => i * 2 + 3).reduce((p, v) => {!~p.findIndex(p_ => !(v % p_)) && p.push(v); return p;}, [2]);
// actually calculating n
var sol = primes.map(p => Math.pow(p, Math.floor(Math.log(n) / Math.log(p))))
.reduce((a, b) => a * b, 1);
// output
document.getElementById('output_id').innerHTML = 'Solution: ' + sol;
}
所以现在只有一个问题需要回答:所有数学的重点是什么?答案:速度(和美丽;))。使用此代码,您可以计算最大<input maxlength="512" id="input_n_id" placeholder="Enter a value here"/>
<button onclick="run()">Start</button>
<p id="output_id">Waiting for input...</p>
的任何数字范围的最小公倍数(实际上您可以更进一步,但从709开始,解决方案超出了javascripts浮点数的范围)。
答案 2 :(得分:0)
您将max设置为20,然后您的循环依赖于2和max(20)之间的所有数字,即n的因子。如果n <20,则该方法将不起作用,因为显然大于n的数字不能是n的因子。如果n
答案 3 :(得分:0)
这是关于素数的。想想哪些素数使得所有数字都在1到20之间,记住计算你需要的每个素数的最小数量,并将它们相乘以得到解。例如,对于9,我们需要两个3,对于16,我们需要4个2,等等。