JavaScriptで2つの配列から作れる最大の数を求める方法
問題
1桁の数字を要素とする2つの配列 arr1 と arr2 を第1・第2引数として受け取り、さらに数値 num(num <= arr1.length + arr2.length)を第3引数として受け取るJavaScript関数を作成します。
この関数が返すのは、長さ num の1桁の数字からなる新しい配列です。この配列自体が1つの数値を表しており、その値は両方の配列の要素を組み合わせて作成できる最大の数でなければなりません。
ただし、重要な条件がひとつあります。それは、同じ配列内の要素の相対的な順序は維持しなければならないという点です。
例えば、関数への入力が次の場合を考えてみましょう。
const arr1 = [1, 3, 4, 5, 6]; const arr2 = [9, 1, 2, 5, 8, 3]; const num = 4;
この場合、期待される出力は次のとおりです。
const output = [9, 8, 6, 3];
つまり、「9863」という最大の数を、各配列の元の順序を崩すことなく作り出しています。
サンプルコード
この問題を解くコードは次のようになります。
const arr1 = [1, 3, 4, 5, 6];
const arr2 = [9, 1, 2, 5, 8, 3];
const num = 4;
const maxArray = (arr1 = [], arr2 = [], num) => {
const map = new Map();
const match = (a, b, num) => {
if (map.has(a + ',' + b + ',' + num)) {
return map.get(a + ',' + b + ',' + num);
}
let output = [];
while(num > 0) {
let maxa = -Infinity;
let maxai = 0;
let maxb = -Infinity;
let maxbi = 0;
for(let i = a; i < arr1.length && arr1.length + arr2.length - (i + b) >= num; i++) {
if (arr1[i] > maxa) {
maxa = arr1[i];
maxai = i;
}
}
for(let i = b; i < arr2.length && arr1.length + arr2.length - (a + i) >= num; i++) {
if (arr2[i] > maxb) {
maxb = arr2[i];
maxbi = i;
}
}
if (maxa === maxb) {
output.push(maxa);
let ca = map.get(a+','+(maxbi+1)+','+(num-1)) || match(a, maxbi+1, num-1);
let cb = map.get((maxai+1)+','+b+','+(num-1)) || match(maxai+1,b,num-1);
map.set(a+','+(maxbi+1)+','+(num-1), ca);
map.set((maxai+1)+','+b+','+(num-1), cb);
if (ca.join('') > cb.join('')) {
return [...output, ...ca];
} else {
return [...output, ...cb];
}
} else if (maxa > maxb) {
output.push(maxa);
a = maxai + 1;
} else {
output.push(maxb);
b = maxbi + 1;
}
num--;
}
map.set(a + ',' + b + ',' + num, output);
return output;
}
return match(0, 0, num);
};
console.log(maxArray(arr1, arr2, num));コードの解説
このアルゴリズムでは、次のような手順で最大の数を組み立てています。
残りの桁数(
num)を満たせる範囲に制限しながら、forループで各配列から選べる最大の数字を探します。arr1側の候補の方が大きければarr1の数字を採用し、そうでなければarr2の数字を採用します。両方の配列に同じ数字がある場合は、どちらを選んでも結果が変わる可能性があるため、再帰的にその後の結果を比較し、より大きな数になる方を選びます。
また、同じ状態(開始位置と残り桁数の組み合わせ)の計算結果を Map オブジェクトにキャッシュすることで、重複する再帰計算を避け、パフォーマンスを向上させています。これはメモ化(memoization)と呼ばれるテクニックです。
出力
コンソールには次のように出力されます。
[ 9, 8, 6, 3 ]
-
JavaScriptで2つの配列間の欠落した数値を見つける方法
問題の概要 2つの配列 arr1 と arr2 を引数として受け取るJavaScript関数を作成します。 arr2 は arr1 の要素をシャッフルした複製ですが、たった1つの要素だけが欠落しています。 この関数の目的は、その欠落している1つの要素を見つけ出して返すことです。 アプローチのポイント 最もシンプルかつ効率的なのは、ハッシュマップ(オブジェクト)を使って各数値の出現回数を記録する方法です。計算量は O(n) に抑えられ、配列内に重複した値が含まれていても正しく動作します。 コード例 以下が実際のコードです。 const arr1 = [6, 1, 3, 6, 8, 2];
-
【JavaScript】2つの配列間の文字列の長さにおける最大絶対差を求める方法
問題 2つの文字列の配列 a1 と a2 を引数として受け取るJavaScript関数を作成する必要があります。各文字列は a〜z の英字のみで構成されているものとします。ここで x を1つ目の配列内の任意の文字列、y を2つ目の配列内の任意の文字列としたとき、関数は次の値を求めます。 max(abs(length(x) − length(y))) つまり、別々の配列に属する文字列のペアごとに長さの差の絶対値を計算し、その中で最大となる値を返すという問題です。 解法のポイント すべての文字列の組み合わせに対して二重ループで差を求めることも可能ですが、より効率的なアプローチがあります。絶対差