これも色んな解法がある!
問題概要
英小文字からなる 3 文字以上 100 文字以下の文字列 が与えられる。
はある 1 文字を除いて全て同じ文字で構成されています。その異なる文字があるのは何文字目か?
制約
解法 (1):全探索
大抵の問題は、まず全探索を考えることでとっかかりが掴めることが多い。この問題も例外ではない。つまり、 について、 の 文字目が条件を満たすかどうかを check する解法を考えよう。条件を満たすような を答えればよいのだ。
の 文字目が条件を満たすかどうかは次のように確認できる。
【条件を満たすかの判定】
任意の () に対して、
であるかどうかを判定する。
以上の解法は、次のような 2 重ループで実装できる。
コード
#include <bits/stdc++.h> using namespace std; int main() { string S; cin >> S; for (int i = 0; i < S.size(); i++) { bool ok = true; for (int j = 0; j < S.size(); j++) { if (j == i) continue; if (S[j] == S[i]) ok = false; } if (ok) { cout << i+1 << endl; return 0; } } }
解法 (2):集計処理
次に、文字列 において、どの文字が何個使われているかを集計する方法を考えよう。次のような配列 num
(C++ では vector<vector<int>>
型などが適切と考えられる)を用意する。
num[c]
:文字列 の中に文字 があるような index を集めたもの
ただし、実際にプログラムでこの配列を実装する際には、文字 'a' には 0 を対応させて、文字 'b' には 1 を対応させて、......文字 'z' には 25 を対応させるとよい。
この配列 num
を作ってしまえば、num[c]
のサイズが 1 であるような文字 に対して、num[c]
に格納された値(答えとなる添字)を答えればよい。
コード
#include <bits/stdc++.h> using namespace std; int main() { string S; cin >> S; vector<vector<int>> nums(26); for (int i = 0; i < S.size(); i++) { nums[S[i] - 'a'].push_back(i); } for (int i = 0; i < 26; i++) { if (nums[i].size() == 1) { cout << nums[i][0] + 1 << endl; return 0; } } }
解法 (3):ソートする
文字列 自体をソートすると、次のいずれかになる。なお、 の文字をソートしてできる文字列を とする。
- 1 文字だけ異なる文字が先頭にあり、それ以外はすべて同じ文字である
- 1 文字だけ異なる文字が末尾にあり、それ以外はすべて同じ文字である
このことから、「1 文字だけ異なる文字」を次のように特定できる( はソートした文字列)。
T[0] == T[1]
のとき:1 文字だけ異なる文字は、 の末尾の文字(T.back()
)である あるT[0] != T[1]
のとき:1 文字だけ異なる文字は、 の先頭の文字(T[0]
)である
こうして、1 文字だけ異なる文字を特定してしまえば、その文字がある index を見つければよい!!
コード
#include <bits/stdc++.h> using namespace std; int main() { string S, T; cin >> S; T = S; sort(T.begin(), T.end()); char c; if (T[0] == T[1]) c = T.back(); else c = T[0]; for (int i = 0; i < S.size(); i++) { if (S[i] == c) { cout << i + 1 << endl; return 0; } } }