JavaScriptでマトリックス(行列)内のラッキーナンバーを見つける方法
すべての要素が互いに異なる m × n 行列が与えられたとき、その中にある「ラッキーナンバー」をすべて見つけて返すのが今回の課題です。
ラッキーナンバーとは、自分の属する行の中で最小値であり、かつ自分の属する列の中で最大値である要素のことを指します。
具体例
たとえば、次のような入力配列を考えてみましょう。
const arr = [ [3,7,8], [9,11,13], [15,16,17] ];
この場合の出力は次のようになります。
const output = [15];
これは、15 が最下行の中で最小の値であり、同時に第1列の中で最大の値でもあるため、この行列における唯一のラッキーナンバーだからです。
解法のコード
const arr = [
[3,7,8],
[9,11,13],
[15,16,17]
];
const luckyNumbers = (arr, res = []) => {
const M = arr.length, N = arr[0].length;
// 各行の最小値を保持する配列
const min = Array(M).fill(Infinity);
// 各列の最大値を保持する配列
const max = Array(N).fill(-Infinity);
// 全要素を一度だけ走査して最小値・最大値を更新
for (let i = 0; i < M; ++i)
for (let j = 0; j < N; ++j)
min[i] = Math.min(min[i], arr[i][j]),
max[j] = Math.max(max[j], arr[i][j]);
// 行の最小値と列の最大値が一致する要素を収集
for (let i = 0; i < M; ++i)
for (let j = 0; j < N; ++j)
if (min[i] === max[j])
res.push(arr[i][j]);
return res;
};
console.log(luckyNumbers(arr));コードのポイント
このアルゴリズムの肝は、行列全体をあらかじめ走査しておき、各行の最小値を格納した配列 min と、各列の最大値を格納した配列 max を作成することです。
その後にもう一度行列を走査し、min[i] と max[j] が一致する位置 (i, j) の要素こそが、「行内で最小・列内で最大」という条件を満たすラッキーナンバーとなります。
なお、すべての数値が互いに異なるという前提があるため、ラッキーナンバーは高々1個しか存在しないという性質もあります。
計算量
- 時間計算量:O(M × N) — 行列の全要素を最大2回走査するため
- 空間計算量:O(M + N) — 行ごとの最小値と列ごとの最大値を保存するため
出力結果
コンソールに出力される結果は以下のとおりです。
[15]
-
JavaScriptの数値(Number)の基本と実践サンプルコード
JavaScriptでは、整数も小数もすべて「Number」型として扱われます。この記事では、数値変数の定義方法と、それらを使った簡単な演算の例を、動作するHTMLサンプルコードとともに紹介します。サンプルコード以下は、JavaScriptで数値を扱う基本的な例です。整数(22、99)と小数(1.523)を変数に格納し、ボタンをクリックすると画面に表示する仕組みになっています。<!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name=viewport co
-
JavaScriptのconstとletの違いを徹底解説!ブロックスコープ変数の基本と使い方
JavaScriptにおけるconstとletの基本const と let は、ES2015(ES6)で導入された変数宣言用のキーワードです。どちらもブロックスコープ(波括弧 { } で囲まれた範囲)に対応しているのが特徴で、関数スコープしか持たなかった従来の var とは異なる挙動を示します。両者の大きな違いは再代入の可否です。letで宣言した変数は後から何度でも値を再代入できますが、constで宣言した変数は再代入しようとするとエラー(TypeError)が発生します。letとconstの主な違い項目letconst再代入可能不可(エラー発生)スコープブロックスコープブロックスコープ宣言時