2つの数値の配列を指定して、数値の範囲の開始と終了を定義させます。例えば、 [2,6]
は、2,3,4,5,6の範囲を意味します。範囲の最小公倍数を見つけるためにjavascriptコードを書きたいです。以下の私のコードは小さな範囲でのみ機能し、[1,13]
(1,2,3,4,5,6,7,8,9,10,11,12,13の範囲)、スタックオーバーフローを引き起こします。範囲の最小公倍数を効率的に見つけるにはどうすればよいですか?
function leastCommonMultiple(arr) {
var minn, max;
if ( arr[0] > arr[1] ) {
minn = arr[1];
max = arr[0];
} else {
minn = arr[0];
max = arr[1];
}
function repeatRecurse(min, max, scm) {
if ( scm % min === 0 && min < max ) {
return repeatRecurse(min+1, max, scm);
} else if ( scm % min !== 0 && min < max ) {
return repeatRecurse(minn, max, scm+max);
}
return scm;
}
return repeatRecurse(minn, max, max);
}
これで仕事が完了すると思います。
function leastCommonMultiple(min, max) {
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.Push(i);
}
return arr;
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range(min, max).forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
leastCommonMultiple(1, 13); // => 360360
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
私は他の答えほど空想的ではありませんが、読みやすいと思います。
function smallestCommons(arr) {
//order our array so we know which number is smallest and which is largest
var sortedArr = arr.sort(sortNumber),
//the smallest common multiple that leaves no remainder when divided by all the numbers in the rang
smallestCommon = 0,
//smallest multiple will always be the largest number * 1;
multiple = sortedArr[1];
while(smallestCommon === 0) {
//check all numbers in our range
for(var i = sortedArr[0]; i <= sortedArr[1]; i++ ){
if(multiple % i !== 0 ){
//if we find even one value between our set that is not perfectly divisible, we can skip to the next multiple
break;
}
//if we make it all the way to the last value (sortedArr[1]) then we know that this multiple was perfectly divisible into all values in the range
if(i == sortedArr[1]){
smallestCommon = multiple;
}
}
//move to the next multiple, we can just add the highest number.
multiple += sortedArr[1];
}
console.log(smallestCommon);
return smallestCommon;
}
function sortNumber(a, b) {
return a - b;
}
smallestCommons([1, 5]); // should return 60.
smallestCommons([5, 1]); // should return 60.
smallestCommons([1, 13]); // should return 360360.
smallestCommons([23, 18]); // should return 6056820.
編集:回答をスニペットに変えました。
範囲[a、b]のLCM関数
// Euclid algorithm for Greates Common Divisor
function gcd(a, b)
{
return !b ? a : gcd(b, a % b);
}
// Least Common Multiple function
function lcm(a, b)
{
return a * (b / gcd(a,b));
}
// LCM of all numbers in the range of arr=[a, b]
function range_lcm(arr)
{
// Swap [big, small] to [small, big]
if(arr[0] > arr[1]) (arr = [arr[1], arr[0]]);
for(x = result = arr[0]; x <= arr[1]; x++) {
result = lcm(x, result);
}
return result;
}
alert(range_lcm([8, 5])); // Returns 840
ちょっと私はこのページに出くわし、私のソリューションを共有したかった:)
function smallestCommons(arr) {
var max = Math.max(arr[0], arr[1]),
min = Math.min(arr[0], arr[1]),
i = 1;
while (true) {
var count = 0;
for (j = min; j < max; j++) {
if (max * i % j !== 0) {
break;
}
count++;
}
if (count === (max - min)) {
alert(max * i);
return max * i;
}
i++;
}
}
smallestCommons([23, 18]);
これは、元のアプローチの非再帰バージョンです。
function smallestCommons(arr) {
// Sort the array
arr = arr.sort(function (a, b) {return a - b}); // numeric comparison;
var min = arr[0];
var max = arr[1];
var numbers = [];
var count = 0;
//Here Push the range of values into an array
for (var i = min; i <= max; i++) {
numbers.Push(i);
}
//Here freeze a multiple candidate starting from the biggest array value - call it j
for (var j = max; j <= 1000000; j+=max) {
//I increase the denominator from min to max
for (var k = arr[0]; k <= arr[1]; k++) {
if (j % k === 0) { // every time the modulus is 0 increase a counting
count++; // variable
}
}
//If the counting variable equals the lenght of the range, this candidate is the least common value
if (count === numbers.length) {
return j;
}
else{
count = 0; // set count to 0 in order to test another candidate
}
}
}
alert(smallestCommons([1, 5]));
function lcm(arr) {
var max = Math.max(arr[0],arr[1]),
min = Math.min(arr[0],arr[1]),
lcm = max;
var calcLcm = function(a,b){
var mult=1;
for(var j=1; j<=a; j++){
mult=b*j;
if(mult%a === 0){
return mult;
}
}
};
for(var i=max-1;i>=min;i--){
lcm=calcLcm(i,lcm);
}
return lcm;
}
lcm([1,13]); //should return 360360.
これは別の非常に簡単な方法であり、複雑さは低いです。
function smallestCommons(arr) {
let smallestNum = arr[0] < arr[1] ? arr[0] : arr[1];
let greatestNum = arr[0] > arr[1] ? arr[0] : arr[1];
let initalsArr = [];
for(let i = smallestNum; i <= greatestNum; i++){
initalsArr.Push(i);
}
let notFoundFlag = true;
let gNMltpl = 0;
let filteredArrLen;
while(notFoundFlag){
gNMltpl += greatestNum;
filteredArrLen = initalsArr.filter((num)=>{
return (gNMltpl / num) === Math.floor((gNMltpl / num))
}).length;
if(initalsArr.length == filteredArrLen){
notFoundFlag = false;
}
}
return gNMltpl;
}
function leastCommonMultiple(arr) {
/*
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.Push(i);
}
return arr;
}
*/
var min, range;
range = arr;
if(arr[0] > arr[1]){
min = arr[1];
}
else{
min = arr[0]
}
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
var multiple = min;
range.forEach(function(n) {
multiple = lcm(multiple, n);
});
return multiple;
}
console.log(leastCommonMultiple([1、13]))
これが私の解決策です。簡単にフォローできることを願っています。
function smallestCommons(arr) {
var min = Math.min(arr[0], arr[1]);
var max = Math.max(arr[0], arr[1]);
var smallestCommon = min * max;
var doneCalc = 0;
while (doneCalc === 0) {
for (var i = min; i <= max; i++) {
if (smallestCommon % i !== 0) {
smallestCommon += max;
doneCalc = 0;
break;
}
else {
doneCalc = 1;
}
}
}
return smallestCommon;
}
ここに別の非再帰的なforループソリューションがあります
function smallestCommons(arr) {
var biggestNum = arr[0];
var smallestNum = arr[1];
var thirdNum;
//make sure biggestNum is always the largest
if (biggestNum < smallestNum) {
thirdNum = biggestNum;
biggestNum = smallestNum;
smallestNum = thirdNum;
}
var arrNum = [];
var count = 0;
var y = biggestNum;
// making array with all the numbers fom smallest to biggest
for (var i = smallestNum; i <= biggestNum; i += 1) {
arrNum.Push(i);
}
for (var z = 0; z <= arrNum.length; z += 1) {
//noprotect
for (y; y < 10000000; y += 1) {
if (y % arrNum[z] === 0) {
count += 1;
break;
}
else if (count === arrNum.length) {
console.log(y);
return y;
}
else {
count = 0;
z = 0;
}
}
}
}
smallestCommons([23, 18]);
誤字のために元々スタックオーバーフローが発生した可能性があります。min
の途中でminn
とrepeatRecurse
を切り替えました(repeatRecurse
が外部関数で定義されていなかった場合は、それをキャッチできます)。これが修正されると、repeatRecurse(1,13,13)
は156を返します。
スタックオーバーフローを回避するための明白な答えは、再帰関数を非再帰関数に変えることです。あなたはそれを行うことによってそれを達成することができます:
_function repeatRecurse(min, max, scm) {
while ( min < max ) {
while ( scm % min !== 0 ) {
scm += max;
}
min++;
}
}
_
しかし、おそらくこの時点で間違いを見ることができます。scm
がmin
の前にある要素で割り切れることを保証しているわけではありません。たとえば、repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20
です。 max
を追加する代わりに、scm
をその最小公倍数でmin
に置き換えます。 rgbchrisのgcdを使用できます(整数の場合、_!b
_は_b===0
_と同じものです)。テールの最適化を維持したい場合(javascriptエンジンにはテールの最適化がないと思いますが)、次のようになります:
_function repeatRecurse(min, max, scm) {
if ( min < max ) {
return repeatRecurse(min+1, max, lcm(scm,min));
}
return scm;
}
_
または再帰なし:
_function repeatRecurse(min,max,scm) {
while ( min < max ) {
scm = lcm(scm,min);
min++;
}
return scm;
}
_
これは、本質的にrgbchrisのソリューションと同等です。よりエレガントな方法は、分割して征服することです:
_function repeatRecurse(min,max) {
if ( min === max ) {
return min;
}
var middle = Math.floor((min+max)/2);
return lcm(repeatRecurse(min,middle),repeatRecurse(middle+1,max));
}
_
2つの数値の配列である元の引数から離れることをお勧めします。 1つには、2つの異なる配列_[min,max]
_と範囲配列について説明することになります。もう1つは、長い配列を渡すのは非常に簡単で、何か間違ったことをしたことに気付かないことです。また、最小値と最大値を決定するための数行のコードが必要です。これらの値は、呼び出し元によって決定されるべきでした。
最後に、本当に大きな数を扱う場合は、数の素因数分解を使用して最小公倍数を見つける方が良い場合があります。
どうですか:
// Euclid Algorithm for the Greatest Common Denominator
function gcd(a, b) {
return !b ? a : gcd(b, a % b);
}
// Euclid Algorithm for the Least Common Multiple
function lcm(a, b) {
return a * (b / gcd(a, b));
}
// LCM of all numbers in the range of arr = [a, b];
function smallestCommons(arr) {
var i, result;
// large to small - small to large
if (arr[0] > arr[1]) {
arr.reverse();
} // only happens once. Means that the order of the arr reversed.
for (i = result = arr[0]; i <= arr[1]; i++) { // all numbers up to arr[1] are arr[0].
result = lcm(i, result); // lcm() makes arr int an integer because of the arithmetic operator.
}
return result;
}
smallestCommons([5, 1]); // returns 60
function smallestCommons(arr) {
var sortedArr = arr.sort(); // sort array first
var tempArr = []; // create an empty array to store the array range
var a = sortedArr[0];
var b = sortedArr[1];
for(var i = a; i <= b; i++){
tempArr.Push(i);
}
// find the lcm of 2 nums using the Euclid's algorithm
function gcd(a, b){
while (b){
var temp = b;
b = a % b;
a = temp;
}
return a;
}
function lcm(a, b){
return Math.abs((a * b) / gcd(a, b));
}
var lcmRange = tempArr.reduce(lcm);
return lcmRange;
}
ソリューションでよくプレイしました。私は将来の参考のために少し短くなるかもしれないものを手に入れたと思うが、あなたのものを間違いなく見て
function LCM(arrayRange) {
var newArr = [];
for (var j = arrayRange[0]; j <= arrayRange[1]; j++){
newArr.Push(j);
}
var a = Math.abs(newArr[0]);
for (var i = 1; i < newArr.length; i++) {
var b = Math.abs(newArr[i]),
c = a;
while (a && b) {
a > b ? a %= b : b %= a;
}
a = Math.abs(c * newArr[i] / (a + b))
}
return console.log(a);
}
LCM([1,5]);
function smallestCommons(arr) {
let smallest, biggest, min;
arr.reduce(function (a, b) {
biggest = Math.max(a, b);
});
const max = biggest;
arr.reduce(function (a, b) {
smallest = Math.min(a, b);
min = smallest;
});
check: while (true) {
biggest += max;
for (min = smallest; min < max; min++) {
if (biggest % min != 0) {
continue check;
}
if (min == (max - 1) && biggest % min == 0) {
console.warn('found one');
return biggest;
}
}
}
}
function smallestCommons(arr) {
let min = Math.min(arr[0], arr[1]);
let max = Math.max(arr[0], arr[1]);
let scm = max;
//calc lcm of two numbers:a,b;
const calcLcm = function(a, b) {
let minValue = Math.min(a, b);
let maxValue = Math.max(a, b);
let lcm = maxValue;
while (lcm % minValue !== 0) {
lcm += maxValue;
}
return lcm;
}
//calc scm in range of arr;
for (let i = max; i >= min; i--) {
scm = calcLcm(scm, i);
}
console.log(scm);
return scm;
}
smallestCommons([1, 13]);
function range(min, max) {
var arr = [];
for (var i = min; i <= max; i++) {
arr.Push(i);
}
return arr;
}
function gcd (x, y) {
return (x % y === 0) ? y : gcd(y, x%y);
}
function lcm (x, y) {
return (x * y) / gcd(x, y);
}
function lcmForArr (min, max) {
var arr = range(min, max);
return arr.reduce(function(x, y) {
return lcm(x, y);
});
}
range(10, 15); // [10, 11, 12, 13, 14, 15]
gcd(10, 15); // 5
lcm(10, 15); // 30
lcmForArr(10, 15); //60060
/*Function to calculate sequential numbers
in the range between the arg values, both inclusive.*/
function smallestCommons(arg1, arg2) {
if(arg1>arg2) { // Swap arg1 and arg2 if arg1 is greater than arg2
var temp = arg1;
arg1 = arg2;
arg2 =temp;
}
/*
Helper function to calculate greatest common divisor (gcd)
implementing Euclidean algorithm */
function gcd(a, b) {
return b===0 ? a : gcd(b, a % b);
}
/*
Helper function to calculate lowest common multiple (lcm)
of any two numbers using gcd function above */
function lcm(a,b){
return (a*b)/gcd(a,b);
}
var total = arg1; // copy min value
for(var i=arg1;i<arg2;i++){
total = lcm(total,i+1);
}
//return that total
return total;
}
/*Yes, there are many solutions that can get the job done.
Check this out, same approach but different view point.
*/
console.log(smallestCommons(13,1)); //360360
</ code>