C++で全ての文字列を一致させるための最小移動回数を求める方法
問題の概要
互いに回転(順列)の関係にある n 個の文字列が与えられます。使用できる操作は「任意の文字列の先頭の1文字を取り出し、その文字列の末尾へ移動する」ことだけです。この操作を繰り返してすべての文字列を同一にするとき、必要となる最小の操作回数を求めます。
例
arr[] = {"abcd", "cdab"} の場合、必要な移動回数は 2 回です。
- 最初の文字列 "abcd" に対して、文字 'a' を末尾へ移動します。操作後の文字列は "bcda" になります。
- 次に、文字 'b' を末尾へ移動します。操作後の文字列は "cdab" となり、2番目の文字列と一致します。
アルゴリズム
- 基準となる文字列を1つ選びます(ここでは str1 と呼びます)。
- str1 を2回連結した一時文字列を作成します。
temp = str1 + str1 - temp の中で他の各文字列を検索し、見つかった位置(インデックス)がその文字列に必要な回転回数になります。
- すべての文字列を基準として上記の手順を繰り返し、得られた回数の中で最も小さい値を答えとして返します。
この手法が成り立つのは、「文字列 s を2回連結した s + s の中には、s のすべての回転パターンが必ず含まれる」という性質があるためです。
C++での実装例
#include <iostream>
#include <string>
#include <algorithm>
#include <climits>
#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
using namespace std;
int minMoves(string str[], int n) {
int minCnt = INT_MAX;
// 各文字列を「目標」として順に試す
for (int i = 0; i < n; ++i) {
int cnt = 0;
for (int j = 0; j < n; ++j) {
string temp = str[j] + str[j];
int index = temp.find(str[i]);
if (index != string::npos) {
cnt += index; // 必要な回転回数を加算
}
}
minCnt = min(cnt, minCnt);
}
return minCnt;
}
int main() {
string str[] = {"abcd", "cdab", "bacd", "cdba"};
cout << "Minimum moves: " << minMoves(str, SIZE(str)) << endl;
return 0;
}実行結果
上記のプログラムをコンパイルして実行すると、次の出力が得られます。
Minimum moves: 2
計算量について
文字列の数を n、文字列の長さを L とすると、すべての文字列のペアに対して部分文字列検索(find)を行うため、時間計算量は O(n² × L) となります。文字列の数や長さが大きい場合は注意が必要ですが、問題の規模が小さい範囲では十分に実用的なアプローチです。
-
C++で文字列を回文にするために必要な最小削除文字数を求める方法
問題の概要長さ n の文字列が与えられたとき、その文字列を回文にするために削除が必要な最小の文字数を求めるのがこの問題の目的です。たとえば、入力文字列が「abcda」の場合、先頭と末尾以外の2文字を削除すれば回文を作ることができます。「b」と「c」を削除すると → 「ada」(回文になります)「c」と「d」を削除すると → 「aba」(回文になります)「b」と「d」を削除すると → 「aca」(回文になります)アルゴリズムの考え方この問題は「最長回文部分列(Longest Palindromic Subsequence: LPS)」の考え方を使うと効率的に解けます。手順は次のとおりです。与えら
-
C++で配列の全要素を同じ値にするための最小削除操作数を求めるアルゴリズム
問題概要n個の要素からなる配列が与えられます。要素には重複が含まれる場合があります。この配列から任意の数の要素を削除できるとき、すべての要素を同じ値にするために必要な最小の削除数を求めるのが課題です。例として、次の配列を考えてみましょう。arr[] = {10, 8, 10, 7, 10, -1, -4, 12}この場合、最も多く出現している「10」以外の5つの要素を削除すれば、配列の全要素を10で統一できます。つまり、答えは5回の削除となります。解法の考え方この問題の鍵となるのは、「削除する量を最小化する = 残す要素の数を最大化する」という発想です。全要素を同じ値にするためには、必ずどれか