そまちょブログのそまちょ(@somachob)です。
この記事は、Sky株式会社プログラミングコンテスト2023(AtCoder Beginner Contest 289)のA問題についての解説です。
C++の基本については、こちらの記事を参考にしてください。
競技プログラミングって何?って方はこちらの記事もぜひ見てみてください。
A – flip
■問題文
0 と 1 の 2 種類の文字からなる文字列 s が与えられます。
s に含まれる 0 を 1 に、1 を 0 に置き換えた文字列を出力してください。■制約
A – flip
- s の長さは 1 以上 10 以下
- s は 0 と 1 の 2 種類の文字からなる
与えられた文字列の 0 と 1 を反転させて出力させます。
入力が 1011 だと、出力は 0100 になります。
受け取った文字列について、1文字ずつ 0 か 1 か判断して、出力する文字を分岐させます。
解答コード
#include <bits/stdc++.h>
using namespace std;
int main () {
// 入力
string s;
cin >> s;
// s について1文字ずつ処理
for (int i = 0; i < s.size(); i++){
// 0 だったときは 1 を出力
if (s[i] == '0') cout << '1';
// 1 だったときは 0 を出力
if (s[i] == '1') cout << '0';
}
return 0;
}
入力された文字列 s の文字数は s.size() で取得することができます。
#include <bits/stdc++.h>
using namespace std;
int main () {
string s1 = "123";
cout << s1.size() << endl; // => 3
string s2 = "hello";
cout << s2.size() << endl; // => 5
return 0;
}
文字列の左から1番目の文字にアクセスするには s[0] と書きます。
1番目の文字は 0 から始まることに注意してください。
#include <bits/stdc++.h>
using namespace std;
int main () {
string s = "123";
cout << s[0] << endl; // => 1
cout << s[1] << endl; // => 2
cout << s[2] << endl; // => 3
return 0;
}
0 か 1 判定している if 文は、else を使って以下のように書くこともできます。
// 0 だったときは 1 を出力
if (s[i] == '0') cout << '1';
// それ以外のときは 0 を出力
else cout << '0';
三項演算子
if 文の分岐は、三項演算子を使うことで短く書くことができます。
条件式 ? 真のとき : 偽のとき
これは以下の if 文と同じになります。
if (条件式) 真のとき
else 偽のとき
#include <bits/stdc++.h>
using namespace std;
int main () {
// 入力
string s;
cin >> s;
// s について1文字ずつ処理
for (int i = 0; i < s.size(); i++){
// 三項演算子で分岐
cout << (s[i] == '0' ? '1' : '0');
}
return 0;
}
文字コード
これまでは、出力する文字は 0 か 1 によって if 文で分岐させていました。
文字コードを使って、次のように出力することもできます。
// s について1文字ずつ処理
for (int i = 0; i < s.size(); i++){
// 出力
cout << (char)('0' + '1' - s[i]);
}
コンピュータは、文字も数値として扱います。 (int) や (char) は、出力するときに () の中の型に変換しています。
#include <bits/stdc++.h>
using namespace std;
int main () {
cout << (int)'0' << endl; // => 48
cout << (int)'1' << endl; // => 49
cout << (int)'a' << endl; // => 97
cout << (int)'b' << endl; // => 98
cout << (char)48 << endl; // => 0
cout << (char)49 << endl; // => 1
cout << (char)97 << endl; // => a
cout << (char)65 << endl; // => A
return 0;
}
char型の 0 と 1 の文字コードはそれぞれ、48と49になります。
- 0 の文字コード:48
- 1 の文字コード:49
これを利用すれば 0 を 1 に、1 を 0 に置き換えることができます。それをしているのが以下のコードです。
(char)('0' + '1' - s[i])
‘0’ + ‘1’ は文字コードの足し算になります。
'0' + '1' => 48 + 49 => 97
したがって、上のコードは次と同じになります。
(char)(97 - s[i]) // '0' + '1' は 97
ここで s[i] が 0 だった場合について考えてみます。0 は文字コードで 48 です。
97 - '0' => 97 - 48 => 49
計算した結果、49 になったので、文字コード 49 に対応する文字 1 が出力されます。
// s[i] が 0 だったとして 97 - '0' => 97 - 48 => 49
(char)(49) // 文字コード 49 に対応する 1 になる
s[i] が 1 だった場合は、(char)(48)になるので、文字コード 48 に対応する文字 0 が出力されます。
// s[i] が 1 だったとして 97 - '1' => 97 - 49 => 48
(char)(48) // 文字コード 48 に対応する 0 になる
文字コードを利用して、以下のコードでも AC になります。
#include <bits/stdc++.h>
using namespace std;
int main () {
// 入力
string s;
cin >> s;
// s について1文字ずつ処理
for (int i = 0; i < s.size(); i++){
// 文字コードを利用して出力
cout << (char)('0' + '1' - s[i]);
}
return 0;
}
for 文
文字列を1文字ずつ処理するために for 文を使っています。
配列などのすべての要素について繰り返し処理したいときは、範囲 for 文を使うことで簡単に書くことができます。
範囲 for 文は、次のように書きます。
for (型 要素1つ分の変数名 : 処理したい変数)
次のコードでは、文字列 s を1文字ずつ char 型の変数 c に代入して処理を繰り返します。
#include <bits/stdc++.h>
using namespace std;
int main () {
string s = "abcdef";
// s について1文字ずつ処理
for (char c : s){
cout << c << endl;
}
return 0;
}
// 出力結果
/*
a
b
c
d
e
f
*/
まとめ
for 文を使って文字列 s について1文字ずつ処理することができます。
文字列 s の文字数は、s.size() で取得できる。
文字列 s の要素にアクセスするためには、s[0] のように書く。1文字目の添え字は、0 になる。
if – else は、三項演算子を使っても書くことができる。三項演算子は、次のように書く。
条件式 ? 真のとき : 偽のとき
文字は、パソコン内では文字コードとして数値で扱われている。
配列などのすべての要素について繰り返すときは、範囲 for 文を使えば簡単に繰り返すことができる。
for (型 要素1つ分の変数名 : 処理したい変数)
競技プログラミングの勉強におすすめの書籍を紹介します。
この中でも、競技プログラミングの鉄則と問題解決力を鍛える!アルゴリズムとデータ構造が特におすすめです。