JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで配列を「2倍関係」を満たすように再配置できるか判定する方法

問題

数値の配列 arr を第一引数(唯一の引数)として受け取るJavaScript関数を作成する必要があります。

配列 arr の長さは必ず偶数であると保証されています。

この関数は、すべての 0 <= i < arr.length / 2 に対して arr[2 * i + 1] = 2 * arr[2 * i] という条件を満たすように並べ替えられる場合にのみ true を返し、そうでなければ false を返す必要があります。

たとえば、関数への入力が次の場合を考えてみましょう。

const arr = [4, -2, 2, -4];

このとき、期待される出力は次のとおりです。

const output = true;

出力の説明

配列を [-2, -4][2, 4] の2つのペアに分割できます。どちらのペアも「隣り合う要素の後ろが前の要素のちょうど2倍」という関係を満たしているため、これらを連結した [-2, -4, 2, 4][2, 4, -2, -4] といった並べ替え結果が条件を満たします。よって答えは true となります。

解決アプローチ

この問題は、ハッシュマップ(オブジェクト)で各数値の出現回数を記録し、値の大小順にペアを消費していくことで効率的に解決できます。ポイントは次のとおりです。

  • キーを数値として昇順にソートしてから処理します。
  • 負の数は、絶対値が大きい側(ソート順で先頭側)から処理し、その半分の値(ゼロに近い側)とのペアを探します。
  • 正の数および0は、小さい側から処理し、その2倍の値とのペアを探します。
  • 必要なペアがマップ上に存在しない場合は、並べ替えが不可能と判断して即座に false を返します。

計算量はソートに伴う O(n log n) となり、大規模な配列でも実用的な速度で動作します。

コード例

const arr = [4, -2, 2, -4];

const canRearrange = (arr = []) => {
    // 各数値の出現回数をカウント
    const map = arr.reduce((acc, num) => {
        acc[num] = (acc[num] || 0) + 1;
        return acc;
    }, {});

    // キーを数値として昇順ソート
    const keys = Object.keys(map)
        .map(key => Number(key))
        .sort((a, b) => a - b);

    for (const key of keys) {
        if (key < 0) {
            // 負の数:半分の値とのペアを確認
            while (map[key] > 0) {
                if (map[key / 2] > 0) {
                    map[key] -= 1;
                    map[key / 2] -= 1;
                } else {
                    return false;
                }
            }
        } else {
            // 正の数・0:2倍の値とのペアを確認
            while (map[key] > 0) {
                if (map[key * 2] > 0) {
                    map[key] -= 1;
                    map[key * 2] -= 1;
                } else {
                    return false;
                }
            }
        }
    }
    return true;
};

console.log(canRearrange(arr));

実行結果

このコードをコンソールで実行すると、次のような出力が得られます。

true

入力配列 [4, -2, 2, -4] は条件を満たす並べ替えが可能であるため、関数は true を返しています。もし余分な要素やペアにならない要素が存在すれば、途中で false が返されます。

  1. JavaScriptのslice()メソッドとは?配列から要素を抽出する方法を実例付きで解説

    slice()メソッドの基本JavaScriptのslice()メソッドは、配列の中から指定した範囲の要素を選び出し、新しい配列として返すメソッドです。元の配列は変更されずそのまま残るため、安全に部分的なデータを取り出したい場合に活用できます。基本構文array.slice(start, end)start:抽出を開始する位置を示す整数(インデックス番号)です。end:抽出を終了する位置を示す整数で、この位置にある要素自体は結果に含まれません。それでは、実際にslice()メソッドをJavaScriptで使ってみましょう。例1:配列の一部を切り取って表示する<!DOCTYPE html&

  2. JavaScriptのArray.values()メソッドとは?使い方とサンプルコードを徹底解説

    JavaScriptのArray.values()メソッドとは? JavaScriptのArray.values()メソッドは、対象の配列に含まれるすべての値を格納したイテレーターオブジェクトを返します。ES2015(ES6)以降で利用可能なこのメソッドは、for...ofループやスプレッド構文([...arr])と組み合わせることで、配列の各要素を効率的に取り出せます。 なお、keys()やentries()がインデックス情報も一緒に返すのに対し、values()は純粋に「値」だけを順番に提供する点が大きな特徴です。 基本構文 arr.values() 引数は不要で、戻り値として新しいArr