JavaScriptで配列のネストされた集合の最長の長さを見つけて返す方法
問題
数値の配列 arr を第一引数(かつ唯一の引数)として受け取るJavaScript関数を作成する必要があります。
長さ N の配列 arr には、0 から N-1 までのすべての整数がちょうど1回ずつ含まれています。この関数では、次のルールに従って構成される集合 S の最長の長さを見つけ、その結果を返す必要があります。ここで、S[i] = {A[i], A[A[i]], A[A[A[i]]], ...} と定義されます。
具体的には、S の最初の要素としてインデックス i の要素 A[i] を選択することから始め、次の要素は A[A[i]]、その次は A[A[A[i]]]… というように順に辿っていきます。そして、S の中に重複する要素が現れる直前で追加を停止します。
例えば、関数への入力が次の場合 −
const arr = [5, 4, 0, 3, 1, 6, 2];
出力は次のようになります −
const output = 4;
出力の説明
各要素の値は以下のとおりです。
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2
このとき、最も長い S[K] の一つは次のようになります。
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}インデックス 0 → 5 → 6 → 2 → 0 と辿ると元の位置に戻るため、重複が発生する直前の要素数である「4」が答えとなります。
アプローチ
この問題は、各インデックスから順に値をたどりながらサイクル(一周して戻ってくる経路)の長さを数えることで解決できます。すでに訪問済みのインデックスは再度調べる必要がないため、visited オブジェクトで管理することで計算量を大幅に削減できます。全体の計算量は O(N) です。
例
以下が実際のコードです −
const arr = [5, 4, 0, 3, 1, 6, 2];
const arrayNesting = (arr = []) => {
// 訪問済みのインデックスを記録するオブジェクト
const visited = {};
// 指定インデックスから辿れる連鎖の長さを再帰的に求める
const aux = (index) => {
if (visited[index]) {
return 0;
}
visited[index] = true;
return aux(arr[index]) + 1;
};
let max = 0;
arr.forEach((n, index) => {
if (!visited[index]) {
max = Math.max(max, aux(index));
}
});
return max;
};
console.log(arrayNesting(arr));コードの説明
visited:一度チェックしたインデックスを記録し、同じ経路を二度以上探索しないためのフラグです。aux(index):指定したインデックスから A[i] → A[A[i]] → … と再帰的に値をたどり、連鎖の長さを返します。訪問済みなら 0 を返します。forEach:まだ訪問していないインデックスを起点としてauxを呼び出し、最大値を更新していきます。
出力
コンソールには次のように出力されます −
4
-
JavaScriptで解く「最長の文字列チェーン」:動的計画法による実装と解説
文字列チェーン(Word Chain)とは ある単語 word1 の任意の位置にちょうど1文字を追加することで word2 と一致させられるとき、word1 は word2 の「先行語(predecessor)」であると定義します。たとえば、「abc」に「a」を挿入すると「abac」になるため、「abc」は「abac」の先行語です。 文字列チェーンとは、[word_1, word_2, ..., word_k](k >= 1)という単語の列で、word_1 が word_2 の先行語、word_2 が word_3 の先行語、という関係が順番に成り立つものを指します。 問題の概要 文字
-
JavaScriptで文字列内の最長連続文字とその出現回数を検索する方法
問題文字列を受け取り、その中で最も長く連続して現れる文字とその連続回数を返すJavaScript関数を作成する必要があります。戻り値は必ず2つの要素を持つ配列とします。1つ目の要素:文字列内で最も多く連続して登場する文字2つ目の要素:その文字が連続して登場した回数解決のアプローチこの問題は、文字列を先頭から1文字ずつ走査し、隣接する文字同士を比較することで解決できます。同じ文字が続いている間はカウントを増やし、異なる文字が出現した時点でカウントをリセットします。その際、これまでに記録した最大連続回数を上回っていれば、その文字と回数を結果として保存していきます。コード例以下が実際のコードです。c