C++で特定の文字をすべて削除した後のASCII値の合計を最小化する方法
文字列が与えられたとき、特定の1文字の出現をすべて削除した後の、各文字のASCII値の合計を最小化することを考えます。例として、「hello」という文字列を扱ってみましょう。この文字列のASCII値の合計は (104 + 101 + 108 + 108 + 111) = 532 となります。次に、各文字の出現回数を確認します。
- h は1回出現するため、コストは 1 × 104 = 104
- e は1回出現するため、コストは 1 × 101 = 101
- l は2回出現するため、コストは 2 × 108 = 216
- o は1回出現するため、コストは 1 × 111 = 111
この中で最も多く出現しているのは l です。したがって、l の出現をすべて削除すれば、合計値は最小化されます。つまり、上記のリストから最大のコストを取り除くことと同じです。最終的な結果は 532 − 216 = 316 となります。
アルゴリズムの考え方はシンプルです。まず文字列全体のASCII値の合計を計算します。次に、文字列に含まれる各文字の出現頻度を数え、「出現回数 × ASCII値」が最大となる文字を特定します。その文字を削除した場合の減少量(最大値)を合計から引いたものが、求める結果となります。
この手法の計算量は、文字列を一度走査して頻度を集計する部分が O(n)、26種類の英小文字を確認する部分が O(26) となるため、全体として O(n) の線形時間で処理できます。ただし、サンプルコードでは英小文字のみを想定している点に注意してください。大文字や数字なども扱う場合は、頻度配列のサイズを拡張する必要があります。
サンプルコード
#include <iostream>
using namespace std;
int minASCIISum(string str, int len) {
int max_val = INT_MIN, sum = 0;
int frequency[26] = { 0 };
for (int i = 0; i < len; i++) {
frequency[str[i] - 'a']++;
sum += (int)str[i];
}
for (int i = 0; i < 26; i++)
max_val = max(max_val, frequency[i] * (i + 'a'));
return (sum - max_val);
}
int main() {
string str = "hello";
int n = str.length();
cout << "Minimized Sum: " << minASCIISum(str, n);
}実行結果
Minimized Sum: 316
このコードでは、まず各文字の頻度を配列に記録しながらASCII値の総和を求め、その後「頻度 × ASCII値」が最大になる文字のコストを計算して総和から差し引いています。hello の場合は l を削除することで 316 という最小値が得られます。
-
C++で繰り返し減算により全要素を等しくした後の最大配列合計を求める方法
n個の要素からなる配列が与えられたとします。このとき、すべての要素を同じ値にした状態での、要素の合計の最大値を求めることを考えます。ただし、許されている操作は「任意の2つの要素を選び、大きい方の値を2つの差(絶対値)で置き換える」というものだけです。例として、配列が [9, 12, 3, 6] の場合を考えてみましょう。この場合の出力は 12 になります。手順の例A[1] を A[1] − A[3] = 12 − 6 = 6 に置き換えます。→ 配列は [9, 6, 3, 6]A[3] を A[3] − A[2] = 6 − 3 = 3 に置き換えます。→ 配列は [9, 6, 3, 3]A[
-
C++で各数値から0をすべて削除した後にa+b=cが成立するかどうかを判定する方法
3つの整数 a、b、c が与えられたとき、それぞれの数値から「0」という桁をすべて取り除いた後も、等式 a + b = c が成り立つかどうかを判定する問題を考えてみましょう。 例として、a = 102、b = 130、c = 2005 の場合を見てみます。各数値から0を削除すると、それぞれ 12、13、25 になります。このとき 12 + 13 = 25 が成立するため、答えは「真(true)」となります。 解決のアプローチ 基本的な考え方はシンプルです。 まず、各数値に含まれる0の桁をすべて削除した新しい数値を作成します。 次に、変換後の a と b を足し合わせた結果が、変換後の c