markdown
はじめに (対象読者・この記事でわかること)
この記事は、これからJavaScriptを使ってコーディングテストに挑戦する方、あるいは過去にテストで「問題文の意味が分からなかった」「実装に時間がかかりすぎた」経験がある方を対象としています。
本記事を読むことで、以下のことができるようになります。
- 出題意図や入力・出力条件を正確に抽出できる
- 典型的な問われやすいアルゴリズムパターンを把握し、適切な解法を選択できる
- コーディング前に疑似コードで設計を固め、実装ミスや無駄なデバッグを減らす
執筆のきっかけは、面接の練習をしている中で「問題文が抽象的で何をすれば良いか分からない」ケースが頻繁に起こり、時間ロスが大きくなる現実を目の当たりにしたことです。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML/CSS の基本的な理解(DOM 操作のイメージが必要になることがあります)
- Node.js 環境で JavaScript を実行できる環境(VS Code など)
- 基本的なアルゴリズム概念(ループ、条件分岐、配列操作など)
問題文の読み取りと背景の整理(概要・背景など)
コーディングテストの質問は、単に「コードを書けば良い」以上の情報が詰め込まれています。
まずは 「何を求められているか」 を正しく把握することが最重要です。典型的な要素は次の通りです。
| 要素 | 具体例 | 見落としがちポイント |
|---|---|---|
| 入力形式 | 配列 numbers: number[]、文字列 s: string など |
配列の長さが 0 のケースや、負の数が含まれるか |
| 出力形式 | 整数、配列、オブジェクト、真偽値 | 出力がソート済みであるか、順序が重要か |
| 制約条件 | 1 ≤ n ≤ 10^5、O(n) で解く必要がある |
時間・メモリ上限を無視すると TLE になる |
| 例示 | 入力例 → 出力例 が 1〜3 個 | 例に含まれないエッジケース(空配列、同一要素)が隠れていることがある |
| 目的 | 「最大の連続部分列の和を求めよ」 など | 「部分列」か「部分配列」かの違いが実装に影響する |
読み取りのコツ
- キーワードをハイライト:
unique,sorted,in-placeなどは実装の制約を示す。 - 制約を数値化:
10^5以上のデータは O(n log n) 以上は危険。 - 疑似コードで要件を箇条書き:
- 入力を取得 → 前処理 → アルゴリズム → 出力
- 例外ケース(空、負、重複)を列挙
こうした前段階が済んでいれば、コードを書く時間が格段に短縮されます。
実装手順とコード例(具体的な手順や実装方法)
以下では、典型的な「配列の重複を除去して昇順に並べ替える」問題を題材に、問題文の分解 → テストケース作成 → アルゴリズム設計 → 実装 の流れを解説します。
ステップ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:アルゴリズム設計
- Set を利用した重複除去(
O(n)) - Array.from で配列化し
sort(O(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 要素のまま Set と Array.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 の組み合わせでシンプルかつ高速に解決。
この記事を通して、問題文を正確に把握し、無駄なデバッグ時間を削減できるようになるはずです。次回は、文字列操作系や非同期処理が絡む問題へのアプローチについて掘り下げる予定です。
参考資料
- MDN Web Docs – Set
- MDN Web Docs – Array.prototype.sort()
- 「プログラミングコンテスト攻略のためのアルゴリズムとデータ構造」 – 近藤 浩一 (技術評論社)
- LeetCode 問題「Remove Duplicates from Sorted Array」解説ページ(英語)