markdown

はじめに (対象読者・この記事でわかること)

この記事は、これからJavaScriptを使ってコーディングテストに挑戦する方、あるいは過去にテストで「問題文の意味が分からなかった」「実装に時間がかかりすぎた」経験がある方を対象としています。
本記事を読むことで、以下のことができるようになります。

  • 出題意図や入力・出力条件を正確に抽出できる
  • 典型的な問われやすいアルゴリズムパターンを把握し、適切な解法を選択できる
  • コーディング前に疑似コードで設計を固め、実装ミスや無駄なデバッグを減らす

執筆のきっかけは、面接の練習をしている中で「問題文が抽象的で何をすれば良いか分からない」ケースが頻繁に起こり、時間ロスが大きくなる現実を目の当たりにしたことです。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • HTML/CSS の基本的な理解(DOM 操作のイメージが必要になることがあります)
  • Node.js 環境で JavaScript を実行できる環境(VS Code など)
  • 基本的なアルゴリズム概念(ループ、条件分岐、配列操作など)

問題文の読み取りと背景の整理(概要・背景など)

コーディングテストの質問は、単に「コードを書けば良い」以上の情報が詰め込まれています。
まずは 「何を求められているか」 を正しく把握することが最重要です。典型的な要素は次の通りです。

要素 具体例 見落としがちポイント
入力形式 配列 numbers: number[]、文字列 s: string など 配列の長さが 0 のケースや、負の数が含まれるか
出力形式 整数、配列、オブジェクト、真偽値 出力がソート済みであるか、順序が重要か
制約条件 1 ≤ n ≤ 10^5O(n) で解く必要がある 時間・メモリ上限を無視すると TLE になる
例示 入力例 → 出力例 が 1〜3 個 例に含まれないエッジケース(空配列、同一要素)が隠れていることがある
目的 「最大の連続部分列の和を求めよ」 など 「部分列」か「部分配列」かの違いが実装に影響する

読み取りのコツ

  1. キーワードをハイライトunique, sorted, in-place などは実装の制約を示す。
  2. 制約を数値化10^5 以上のデータは O(n log n) 以上は危険。
  3. 疑似コードで要件を箇条書き
    - 入力を取得 → 前処理 → アルゴリズム → 出力
    - 例外ケース(空、負、重複)を列挙

こうした前段階が済んでいれば、コードを書く時間が格段に短縮されます。

実装手順とコード例(具体的な手順や実装方法)

以下では、典型的な「配列の重複を除去して昇順に並べ替える」問題を題材に、問題文の分解 → テストケース作成 → アルゴリズム設計 → 実装 の流れを解説します。

ステップ1:問題文を分解し要件を明文化

問題例

与えられた整数配列 arr に重複が含まれる場合は重複を除去し、結果を昇順にソートした配列として返してください。配列の長さは 0〜10^5、整数は -10^9〜10^9 の範囲です。

要件の抽出

要件 内容
入力 arr: number[]
出力 number[](重複なし・昇順)
制約 0 ≤ arr.length ≤ 100000-10^9 ≤ arr[i] ≤ 10^9
時間計算量 O(n log n) 以内が安全
エッジケース 空配列、全要素が同じ、負の数が混在

ステップ2:テストケースを自分で作成する

Js
// 正常系 assert.deepStrictEqual(removeDupSort([3,1,2,3]), [1,2,3]); assert.deepStrictEqual(removeDupSort([-1,0,-1,5]), [-1,0,5]); // 境界系 assert.deepStrictEqual(removeDupSort([]), []); assert.deepStrictEqual(removeDupSort([42]), [42]); // 大規模データ(手動で生成) const large = Array.from({length: 100000}, (_,i)=>i%5000); console.time('large'); removeDupSort(large); console.timeEnd('large'); // 約 30ms 程度で終われば OK

ステップ3:アルゴリズム設計

  1. Set を利用した重複除去O(n)
  2. Array.from で配列化し sortO(m log m)m は重複除去後の要素数)

この組み合わせで、最大 n = 10^5 のケースでも十分高速です。

ステップ4:実装

Js
/** * 配列の重複除去と昇順ソート * @param {number[]} arr * @returns {number[]} */ function removeDupSort(arr) { // 0. 入力が配列であることを保証(テスト環境によっては省略可) if (!Array.isArray(arr)) throw new TypeError('arr must be an array'); // 1. Set による重複除去 const uniq = new Set(arr); // O(n) // 2. 配列化してソート const result = Array.from(uniq).sort((a, b) => a - b); // O(m log m) return result; }

ハマった点やエラー解決

発生した問題 原因 解決策
TypeError: arr.sort is not a function Set のまま sort を呼び出した Array.from で配列に変換
ソートが文字列として行われた arr.sort() のデフォルト比較は文字列 数値比較関数 (a,b)=>a-b を指定
メモリ使用量が大きい arr が 10^5 要素のまま SetArray.from を同時保持 実装は OK(最大でも約 2 倍のメモリ)だが、環境が限られる場合はインプレースで処理

解決策の詳細

  • Set → Array の変換忘れ は初心者が陥りやすい落とし穴です。Array.from またはスプレッド構文 [...uniq] を使えばすぐに解決できます。
  • 比較関数の指定 は、負の数が混在するケースで特に重要です。a - b が最もシンプルで正確です。

補足:時間計算量と最適化

  • Set の挿入は平均 O(1)、最悪 O(n) ですが実務ではほぼ一定です。
  • sort の内部実装は V8 では Timsort(安定)で O(m log m)
  • もし O(n) のソリューションが求められるなら、計数ソート(整数範囲が狭い場合)や バケットソート を検討しますが、今回の制約では不要です。

まとめ

本記事では、JavaScript のコーディングテストで出題意図を正しく読み解く手順と、代表的な配列重複除去・ソート問題の実装例を紹介しました。

  • 問題文の要件抽出:入力・出力・制約を表形式で整理し、エッジケースを洗い出す。
  • テストケースの自作:正解・境界・大規模データで網羅的に検証。
  • アルゴリズム設計と実装:Set + sort の組み合わせでシンプルかつ高速に解決。

この記事を通して、問題文を正確に把握し、無駄なデバッグ時間を削減できるようになるはずです。次回は、文字列操作系や非同期処理が絡む問題へのアプローチについて掘り下げる予定です。

参考資料