我正在尝试解决本周大部分时间困扰我的freeCodeCamp challenge。
我希望获得有关特定内容的帮助和指导,但不一定是freeCodeCamp挑战的完整解决方案。
问题如下:
中间算法脚本:最小公倍数
找到所提供的参数的最小公倍数,可以将它们以及这些参数之间的范围内的所有序号均分。
范围将是两个数字的数组,不一定按数字顺序。
例如,如果给定1和3,则求出1和3的最小公倍数,该公倍数也可被1和3之间的所有数字整除。这里的答案是6。
这是我到目前为止的内容:
function smallestCommons(arr) {
var sortedArr = arr.sort(function (a, b) { return a - b });
var startingPoint = sortedArr[0]; var endingPoint = sortedArr[1];
var arrRange = []; // contains numbers from startingPoint to
// endingPoint thanks to for loop
for (var i = startingPoint; i < endingPoint + 1; i++) {
arrRange.push(i);
}
}
smallestCommons([1, 5]);
我的游戏计划是要有另一个遍历巨大数字范围的for循环,并且在巨大数字范围内的每个数字都要经过一个条件,该条件检查迭代的每个数字是否可被arrRange
中的每个数字整除。实际上,这意味着有两个数组彼此迭代吗?
我将如何实现这一目标?
首先,找到数组所有元素的LCM:
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int lcm_array(int arr[], int n) {
int lcm = arr[0];
for (int i = 1; i < n; i++) {
lcm = (arr[i] * lcm) / gcd(arr[i], lcm);
}
return lcm;
}
然后,遍历数组并检查lcm与元素之间的任何除法是否为奇数。如果是,则将lcm乘以2,然后继续直到完成:
int arr[] = { ... };
int lcm = lcm_array(arr, arr_size);
for(int i = 0; i < arr_size; i++){
if( (lcm / arr[i]) % 2 == 1 ) lcm *= 2;
}
print(lcm);
您的游戏计划效率不高。提出的问题实际上转化为在该范围内的所有数字(包括两个输入值)中找到最小公倍数(LCM)。
LCM操作是关联的,并且遵循this rule:
如果a 1,a 2,…,a r都不为零,则
lcm(a 1,a 2,…,a r)= 1cm(lcm(a 1,a 2,…, a r-1),a r)。
因此,这意味着您可以将lcm(a 1,a 2)计算为第一个结果,然后使用该值来处理下一个值:lcm(result,a 3),...等等。这就是通过LCM操作称为reducing的数字范围,因此,该算法确实是使用reduce
方法的不错选择:
reduce
关于定义const gcd = (a, b) => b ? gcd(b, a % b) : a;
const lcm = (a, b) => a * b / gcd(a, b);
const range = (a, b) => Array.from({length: b - a}, (_, i) => a + i);
const smallestCommons = ([a, b]) =>
range(Math.min(a, b), Math.max(a, b) + 1).reduce(lcm);
// Run it:
console.log(smallestCommons([23, 18])); // 6056820
和gcd
的功能,请参见lcm
和Wikipedia on lcm using gcd
用于创建范围,使用on the recursive version of the Eucledian algorithm。 Array.from
函数使用它来生成数组[a,a + 1,...,b-1],因此不包含b。
我使用了箭头函数符号,最后每个函数体只是一个表达式。
如果您不习惯使用箭头函数,进行解构,缩小和/或递归,则此版本仅具有简单的JavaScript构造:
Array.from