C++で文字から構築できる最長回文の長さを求める方法
本記事では、C++を使って「与えられた文字列の文字から構築できる最長回文の長さ」を求めるアルゴリズムを解説します。
問題の概要
小文字・大文字の英字のみで構成された文字列が与えられたとき、それらの文字を自由に並べ替えて作れる最長の回文の長さを求めます。なお、この問題では大文字と小文字は区別されるため、「Aa」のような組み合わせは回文とはみなされません。
例えば、入力が "abccccdd" の場合、出力は 7 になります。これは、"dccaccd" のような長さ7の回文を構築できるためです。
解法のアプローチ
回文の性質に着目すると、以下のように考えることができます。
- 偶数個出現する文字は、すべて左右対称に配置できるため全て使えます。
- 奇数個出現する文字は、そのうち1種類だけ中央に置くことができます(残りは偶数分のみ使用)。
この考え方をもとに、次の手順で解きます。
- 各文字の出現回数を記録するマップ
mpを定義します。 - 文字列
s内の各文字について、mpのカウントを1ずつ増やします。 - 変数
ma = 0(奇数個出現した文字の種類数)、c = 0(文字の総数)、ans = 0(答え)を初期化します。 - マップ内の各キーと値のペアを走査し、値が奇数なら
maを1増やします。また、cに出現回数を加算します。 ma > 0なら、maを1減らします(中央に置ける文字は1つのため)。ans = c - maを計算して返します。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int longestPalindrome(string s) {
unordered_map<char, int> mp;
for (auto i : s)
mp[i]++;
int ma = 0, c = 0, ans = 0;
for (auto i : mp) {
if ((i.second) % 2 == 1)
ma++;
c += i.second;
}
if (ma > 0)
ma--;
ans = c - ma;
return ans;
}
};
main(){
Solution ob;
cout << (ob.longestPalindrome("abccccdd"));
}入力
"abccccdd"
出力
7
計算量
このアルゴリズムの時間計算量は O(n)(n は文字列の長さ)、空間計算量は O(1) です。マップに格納されるキーの種類数は英字52種類に限定されるためです。
-
C++でN以上の最小の素数回文(プライムパリンドローム)を求める方法
この記事では、「N 以上の整数の中で最小となる素数回文(プライムパリンドローム)」を C++ で求めるアルゴリズムを解説します。 例えば N = 13 の場合、答えは 101 になります。13 以上の回文数には 22、33、44 などがありますが、これらはすべて 11 の倍数であるため素数になり得ません。そのため、次に現れる素数回文である 101 が答えとなります。 解法のアプローチ 全ての整数を順に素数かつ回文かどうか調べるのは非効率です。そこで、回文を直接生成することで探索範囲を大幅に絞り込みます。手順は以下の通りです。 N が 8 以上 11 以下の場合は、11 を返します(この範囲
-
C++で回文を壊す:辞書順最小の非回文文字列を作るアルゴリズム
問題概要 回文(前から読んでも後ろから読んでも同じになる文字列)が与えられます。この文字列に対して、ちょうど1文字を任意の小文字の英字に置き換え、回文ではなくなる文字列のうち辞書順最小のものを作ります。そして、その結果得られる最終的な文字列を求めてください。どうしても回文を壊せない場合は、空文字列を返します。 例えば、入力が "abccba" の場合、出力は aaccba となります。 解法のアプローチ この問題は貪欲法(グリーディ法)を使うことで効率的に解けます。辞書順最小の文字列を作るには、「可能な限り前方の文字を小さくする」という性質を利用するのがポイントです。 アル