けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 342 A - Yay! (6Q, 灰色, 150 点)

これも色んな解法がある!

問題概要

英小文字からなる 3 文字以上 100 文字以下の文字列  S が与えられる。

 S はある 1 文字を除いて全て同じ文字で構成されています。その異なる文字があるのは何文字目か?

制約

  •  3 \le |S| \le 100

解法 (1):全探索

大抵の問題は、まず全探索を考えることでとっかかりが掴めることが多い。この問題も例外ではない。つまり、 i = 1, 2, \dots, |S| について、 S i 文字目が条件を満たすかどうかを check する解法を考えよう。条件を満たすような  i を答えればよいのだ。

 S i 文字目が条件を満たすかどうかは次のように確認できる。


【条件を満たすかの判定】
任意の  j = 1, 2, \dots, |S| ( j \neq i) に対して、

 S_{j} \neq S_{i}

であるかどうかを判定する。


以上の解法は、次のような 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):集計処理

次に、文字列  S において、どの文字が何個使われているかを集計する方法を考えよう。次のような配列 num(C++ では vector<vector<int>> 型などが適切と考えられる)を用意する。


  • num[c]:文字列  S の中に文字  c があるような index を集めたもの

ただし、実際にプログラムでこの配列を実装する際には、文字 'a' には 0 を対応させて、文字 'b' には 1 を対応させて、......文字 'z' には 25 を対応させるとよい。

この配列 num を作ってしまえば、num[c] のサイズが 1 であるような文字  c に対して、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):ソートする

文字列  S 自体をソートすると、次のいずれかになる。なお、 S の文字をソートしてできる文字列を  T とする。


  • 1 文字だけ異なる文字が先頭にあり、それ以外はすべて同じ文字である
  • 1 文字だけ異なる文字が末尾にあり、それ以外はすべて同じ文字である

このことから、「1 文字だけ異なる文字」を次のように特定できる( T はソートした文字列)。


  • T[0] == T[1] のとき:1 文字だけ異なる文字は、 T の末尾の文字(T.back())である ある
  • T[0] != T[1] のとき:1 文字だけ異なる文字は、 T の先頭の文字(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;
        }
    }
}