【JavaScript】文字の並べ替えなしで、一方の文字列から一部の文字を削除してもう一方の文字列を形成できるか判定する方法
課題
JavaScriptで、2つの文字列(str1 と str2)を引数として受け取る関数を実装します。この関数は、str1から一部の文字を削除することでstr2を形成できるかどうかを判定します。ただし、文字の並び順を一切変えてはいけないという条件が付きます。
言い換えれば、これは「str2 が str1 の部分列(サブシーケンス)であるか」を調べる問題です。使用する文字の種類や数が揃っているだけでは不十分で、出現順序まで一致している必要がある点がポイントです。
入力例
const str1 = 'sjkfampeflef'; const str2 = 'sample';
この場合、'sample' の各文字が 'sjkfampeflef' の中に左から順に見つかるため、結果は true となります。
解決アプローチ:ツーポインタ法
並び順を保ったまま効率よく判定するには、2つのインデックス(ポインタ)を使った線形走査が有効です。
str1を先頭から走査するポインタjと、str2側の現在位置を示すポインタiを用意する。str1[j]とstr2[i]が一致したらiを1つ進める。- 走査終了時に
iがstr2.lengthに達していれば、str2の全文字を順序どおりに見つけられたことになるのでtrueを返す。
この方法なら計算量は O(n)(n は str1 の長さ)に抑えられ、配列への分割や splice などの余分な操作も不要になります。
コード例
const str1 = 'sjkfampeflef';
const str2 = 'sample';
const checkConvertibility = (str1 = '', str2 = '') => {
// どちらかが空なら形成できない
if (!str1 || !str2) {
return false;
}
let i = 0; // str2 側のポインタ
for (let j = 0; j < str1.length && i < str2.length; j++) {
if (str1[j] === str2[i]) {
i++;
}
}
// str2 の最後まで到達できれば部分列
return i === str2.length;
};
console.log(checkConvertibility(str1, str2));
出力
true
注意点
indexOf や includes で「その文字が存在するか」だけを確認する実装では、並び順が崩れるケース(例:'elmpsa' から 'sample' を作る場合など)を誤って true と判定してしまうおそれがあります。順序が重要な要件では、必ず上記のように順序を考慮した走査を行いましょう。
また、空文字列の扱いは仕様によって変わります。ここでは「どちらかが空なら false」としていますが、「空文字列は常に形成可能」としたい場合は冒頭のガード節を外すだけで対応できます。
-
Pythonで1つ目の文字列の文字から2つ目の文字列を作成できるか判定する方法
問題の概要2つの文字列 s と t が与えられたとき、t を s に含まれる文字だけを使って作れるかどうかを判定する問題です。ここで重要なのは、s の各文字は一度しか使えないという点です。例えば、入力が s = owleh、t = hello の場合、s の文字を組み合わせることで t が作れるため、出力は True になります。解決のアプローチこの問題は「文字の出現回数(頻度)を数える」というシンプルな発想で解けます。手順は以下の通りです。s の各文字とその出現回数を記録したマップ(freq)を作成するt の先頭から順に各文字を確認するfreq[t[i]] が 0 の場合、必要な文字がもう残
-
Pythonで文字列のすべての文字を使ってk個の回文を作成できるかどうかを判定する方法
問題概要 文字列 s と整数 k が与えられたとき、s に含まれるすべての文字を使って、ちょうど k 個の回文(前から読んでも後ろから読んでも同じになる文字列)を作成できるかどうかを判定します。 たとえば、入力が s = amledavmel、k = 2 の場合、「level」と「madam」という2つの回文を作成できるため、出力は True になります。 解法の考え方 回文の性質に注目すると、この問題は非常にシンプルに解けます。回文では、奇数回出現できる文字は最大で1種類だけです。したがって、文字列のすべての文字を k 個の回文に振り分けられる条件は、「奇数回出現する文字の種類数が k 以