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

JavaScriptで0と1を使って形成できる文字列の数を動的計画法で求める方法


問題概要

「0」と「1」のみで構成された文字列の配列 arr を第1引数として受け取るJavaScript関数を作成します。

第2引数と第3引数には、それぞれ2つの整数 m と n が渡されます。この関数の役割は、配列 arr の中から、最大 m 個の「0」と最大 n 個の「1」を使用して形成できる文字列がいくつあるかを求めることです。

入力例

const arr = ["10", "0001", "111001", "1", "0"];
const m = 5, n = 3;

出力例

const output = 4;

出力の説明

5個の「0」と3個の「1」を使って形成できる文字列は、以下の4つです。

"10", "0001", "1", "0"

なお「111001」には1が4つ含まれているため、利用できる「1」の上限(3個)を超えてしまい、選択することはできません。

解法のポイント:動的計画法(DP)

この問題は、いわゆる「0/1ナップサック問題」の応用として捉えることができます。各文字列を1つのアイテムとみなし、「0の使用可能数」と「1の使用可能数」という2つの制約を持つナップサックに、最大でいくつのアイテムを詰め込めるかを求めるイメージです。

具体的な手順は以下の通りです。

  • まず、各文字列に含まれる「0」と「1」の個数をカウントします。
  • 次に、(m+1) × (n+1) のサイズを持つ二次元DPテーブルを用意します。dp[j][k] は「0を最大 j 個、1を最大 k 個使って形成できる文字列の最大数」を表します。
  • 各文字列について、テーブルを大きいインデックス側から順に更新していきます。これにより、同一の文字列が重複してカウントされるのを防ぐことができます。

状態遷移は次の式で表されます。

dp[j][k] = Math.max(dp[j][k], dp[j - zeros][k - ones] + 1);

実装コード

const arr = ["10", "0001", "111001", "1", "0"];
const m = 5, n = 3;
const findAllStrings = (arr = [], m = 1, n = 1) => {
    const getCount = str => str.split('').reduce((acc, cur) => {
        cur === '0' ? acc.zeros++ : acc.ones++;
        return acc;
    }, {zeros:0, ones:0});
    const dp = Array.from({length: m+1}, () => Array(n+1).fill(0));
    for(let i = 0; i < arr.length; i++) {
        const {zeros, ones} = getCount(arr[i]);
        for(let j = m; j >= zeros; j--) {
            for(let k = n; k >= ones; k--) {
                dp[j][k] = Math.max(dp[j-zeros][k-ones]+1, dp[j][k]);
            }
        }
    }
    return dp[m][n]
};
console.log(findAllStrings(arr, m, n));

出力結果

コンソールには以下の値が出力されます。

4
  1. JavaScriptのTextEncoderとTextDecoderとは?文字列とバイト列の相互変換をわかりやすく解説

    JavaScriptでは、文字列とバイト列(バイナリデータ)を相互に変換したい場面がよくあります。そんなときに活躍するのが、TextEncoderとTextDecoderという2つの標準組み込みAPIです。本記事では、それぞれの役割と基本的な使い方を、実際に動くサンプルコードとともに解説します。 TextEncoderとは TextEncoderは、指定した文字列をUTF-8形式に変換(エンコード)するためのオブジェクトです。encode()メソッドに文字列を渡すと、変換結果がUint8Array(符号なし8ビット整数の配列)として返されます。 TextDecoderとは TextDecod

  2. JavaScriptで文字列内の文字を英字・数字・特殊文字に再グループ化する方法

    問題文字列 str を第一引数(唯一の引数)として受け取る JavaScript 関数を作成する必要があります。この文字列には、次の3種類の文字が含まれる可能性があります。英字:(A-Z)、(a-z)数字:0〜9特殊文字:上記以外のすべての文字関数は文字列を先頭から順に走査し、ちょうど3つの要素からなる配列を構築します。1番目の要素には文字列に含まれるすべての英字、2番目には数字、3番目には特殊文字を格納し、それぞれ元の文字列内での出現順(相対的な順序)を維持します。最後にこの配列を返します。例えば、関数への入力が次の場合を考えてみましょう。入力const str = thi!1s is S@