C++で文字列を回文にするために必要な最小の追加文字数を求める方法
問題文
文字列が与えられたとき、その文字列を回文にするために末尾へ追加する必要のある最小の文字数を求めます。
例
たとえば文字列が「abcac」の場合、2文字を追加して「abcacba」とすれば回文になります。
アルゴリズム
- 文字列がすでに回文であるかどうかを確認します。回文であれば、文字を追加する必要はありません。
- 文字列の先頭から1文字ずつ削除し、残りの文字列が回文になっているかどうかを確認します。
- 文字列が回文になるまで、上記の処理を繰り返します。
- それまでに削除した文字数を、最終的な答えとして返します。
このアプローチのポイントは、「先頭から削除した文字数」がそのまま「末尾に追加すべき文字数」に対応するという点です。先頭の文字を取り除いて残りが回文になれば、取り除いた文字を逆順に末尾へ付け足すことで必ず回文が完成します。
サンプルコード
#include <iostream>
#include <cstring>
using namespace std;
bool isPalindrome(char *str) {
int n = strlen(str);
if (n == 1) {
return true;
}
int start = 0, end = n - 1;
while (start < end) {
if (str[start] != str[end]) {
return false;
}
++start;
--end;
}
return true;
}
int requiredAppends(char *str) {
if (isPalindrome(str)) {
return 0;
}
return 1 + requiredAppends(str + 1);
}
int main() {
char *str = "abcac";
cout << "Characters to be appended = " << requiredAppends(str) << endl;
return 0;
}
コードの解説
isPalindrome 関数は、文字列の先頭と末尾から順に文字を比較していくことで、その文字列が回文かどうかを判定します。両端のポインタ start と end を中央に向かって移動させ、不一致が1つでも見つかれば false を返します。
requiredAppends 関数は再帰的に呼び出されます。まず現在の文字列が回文かどうかを判定し、回文でなければ先頭の1文字をスキップした残りの文字列に対して自分自身を呼び出します。回文が見つかった時点で、それまでにスキップした文字数の合計(=末尾に追加すべき文字数)が確定します。
計算量は、最悪の場合に回文判定を文字数の回数だけ繰り返すため O(n²) となります。文字列が短い場合には十分実用的なシンプルな実装です。
出力
上記のプログラムをコンパイルして実行すると、次の出力が得られます。
Characters to be appended = 2
-
C++で数値が回文数かどうかを判定する方法
この記事では、ある数値が回文数(パリンドローム)かどうかを判定する方法を解説します。回文数とは、前から読んでも後ろから読んでも同じになる数値のことです。例えば、12321 は回文数ですが、12345 は回文数ではありません。判定のロジックは非常にシンプルです。数値を逆順に並べ替え、元の数値と一致するかどうかを比較します。一致すれば回文数、一致しなければ回文数ではありません。より理解を深めるために、アルゴリズムを見ていきましょう。アルゴリズムisPalindrome(n) −入力 − 数値 n出力 − 数値が回文数であれば true、そうでなければ false 0, do rev
-
Pythonで文字列を回文にするために必要な最小挿入文字数を求めるプログラム
問題の概要 文字列 s が与えられたとき、その文字列を回文(前から読んでも後ろから読んでも同じになる文字列)にするために、最低何文字を挿入する必要があるかを求める問題です。 例えば、s = mad の場合、出力は 2 になります。「am」を挿入して「madam」にすれば回文になるためです。 解決のアプローチ この問題は、区間ごとに状態を管理する再帰的な動的計画法(DP)で効率よく解けます。以下の手順で考えます。 dp(i, j) という関数を定義します。これは、部分文字列 s[i..j] を回文にするために必要な最小挿入文字数を返します。 i >= j の場合(部分文字列が空、または