2026.01.02일자 입니다. 문자열 부터 2차원 배열까지 몇 문제 풀어보았습니다.
11720번 숫자의 합
#include <iostream>
#include <string>
using namespace std;
int main() {
int N, res = 0; string num; cin >> N >> num;
for (int c : num) res += c - '0';
cout << res;
}
가장 기본적인 방법입니다. 문자 '0'~'9'의 아스키 값을 0~9로 변환하기 위해 '0'을 뺍니다. std::string이 시퀀스 컨테이너이므로 for(int c : num)으로 작성이 가능합니다.
해당 문제를 scanf를 사용하여 풀면 배열을 사용하지 않고도 풀 수 있습니다.
#include <stdio.h>
int main() {
int N, res = 0; scanf("%d", &N);
while (N--) { int t; scanf("%1d", &t); res += t; }
printf("%d", res);
}
%1d로 설정하면 한 문자만 입력 받습니다. 조건이 변경되거나 하는 경우에는 string을 사용하는 것이 안정성이 높습니다. 이러한 방법이 있다는 것만 알아두면 될 것 같습니다.
1152번 단어의 개수
문제 링크
공백을 기준으로 문자의 개수를 세면 되지만 앞 뒤로 공백이 입력될 수 있기 때문에 주의해야 합니다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str; int cnt = 1; getline(cin, str);
for (int i = 0; i < str.length(); i++) if (str[i] == ' ') ++cnt;
if (str[0] == ' ') --cnt; if (str[str.length() - 1] == ' ') --cnt;
cout << cnt;
}
처음에는 if 조건을 아래처럼 작성하였습니다.
i != 0 && i != str.length() - 1 && str[i] == ' '
이렇게 하니 공백만 입력된 경우를 걸러낼 수 없어 연산이 진행되지 않은 cnt 그대로인 1을 출력하였습니다. 따라서 for 루프를 끝낸 이후 앞 뒤가 공백이라면 개수를 줄이는 방식을 선택하였습니다.
또한 해당 코드에서 cin을 사용하면 제대로 동작하지 않습니다. cin은 공백 문자를 만나는 순간 입력을 끝내기 때문에 한 줄을 입력 받기 위해서는 getline(cin, str)를 사용해야 합니다.
trim 함수를 구현하는 방법을 고려했으나 공백은 연속 입력되지 않으므로 구현하지 않았습니다. 구현한다면 다음과 같이 구현할 수 있습니다.
string trim(string str) {
str.erase(0, str.find_first_not_of(' '));
str.erase(str.find_last_not_of(' ') + 1);
return str;
}
erase 메서드는 문자열에서 해당 범위를 지웁니다. erase(index, count)는 index로부터 count개의 문자를 지웁니다. erase(index)만 입력된다면 index부터 끝까지 삭제합니다.
find_first_not_of(value) 메서드는 문자열을 처음부터 탐색하여 처음으로 value가 아닌 문자가 나온 위치를 반환합니다. str.erase(0, str.find_first_not_of(' '));는 맨 앞부터 처음으로 공백이 아닌 문자 전까지 삭제합니다.
반면 find_last_not_of(value) 메서드는 문자열을 뒤에서부터 탐색하여 처음으로 value가 아닌 문자가 나온 위치를 반환합니다. str.erase(str.find_last_not_of(' ') + 1);는 뒤에서 처음으로 공백이 아닌 문자 뒤부터 끝까지 모두 삭제합니다.
5622번 다이얼
#include <iostream>
#include <string>
using namespace std;
int main() {
string num_pad[8] = { "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ" };
string T; cin >> T; int n = 0;
for (char c : T) {
for (int i = 0; i < 8; i++) {
if (num_pad[i].find(c) != string::npos)
n += 3 + i;
}
} cout << n;
}
저는 find 메서드를 사용하여 풀었습니다. 해당하는 문자가 없을 때 false를 반환하는 게 아니라 string::npos를 반환하기 때문에 위와 같이 작성해야 합니다.
하지만
int num_pad[26] = {3, 3, 3, 4, 4, 4, ...};
// ...
for (int c : T) n += num_pad[c - 'A'];
중첩반복문을 사용하지 않는 아래 코드가 더 좋은 것 같습니다.
11718번 그대로 출력하기
EOF를 사용한 문제입니다. 어제 배운 게 생각나서 응용해서 풀어보았습니다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str; while (getline(cin, str)) cout << str << '\n';
}
입력 내에 공백이 입력될 수 있는 것을 간과하고 cin을 사용했다가 오답 처리 되었습니다. getline은 cin을 리턴하기 때문에 eof가 입력되면 false가 반환되는 것입니다.
1157번 단어 공부
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
int cnt[26] = { 0, }; string T; cin >> T;
for (int c : T) ++cnt[c >= 'a' ? c - 'a' : c - 'A'];
if (count(cnt, cnt + 26, *max_element(cnt, cnt + 26)) >= 2) cout << '?';
else cout << (char)(max_element(cnt, cnt + 26) - cnt + 'A');
}
아스키코드를 이용하여 풀었습니다. max_element 가 반환하는 주솟값에 cnt를 빼주어야 배열 시작으로부터 인덱스가 나옵니다.
2941번 크로아티아 알파벳
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main() {
string croatia[] = { "c=", "c-", "dz=", "d-", "lj", "nj", "s=", "z=" };
string T; cin >> T;
for (string s : croatia) {
while (T.find(s) != string::npos) {
T.replace(T.find(s), s.length(), "*");
}
} cout << T.length();
}
크로아티아 문자를 찾아 *로 치환한 후 문자열 길이를 출력합니다.
1316번 그룹 단어 체커
#include <iostream>
#include <string>
using namespace std;
int main() {
int N; cin >> N; int cnt = N;
while (N--) {
string T; int idx = 0; bool check[26] = { 0, }; cin >> T;
for (int c : T) {
if (check[c - 'a'] == 0 || idx == c - 'a') {
idx = c - 'a'; check[idx] = 1;
}
else { --cnt; break; }
}
} cout << cnt;
}
새로 등장한 문자이거나 현재 그 문자가 아니면 cnt를 1 줄이고 검사를 끝냅니다.
2566번 최댓값
문제 링크
2차원 배열에서 최댓값과 그 위치를 구하는 문제입니다. 2차원 배열 문제이므로 vector를 이용해 풀어보았습니다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<vector<int>> v;
for (int i = 0; i < 9; ++i) {
vector<int> t;
for (int j = 0; j < 9; ++j) { int n; cin >> n; t.push_back(n); }
v.push_back(t);
}
int maximum = -1, row = 0, col = 0;
for (int i = 0; i < 9; ++i) {
auto t = max_element(v[i].begin(), v[i].end());
if (*t > maximum) { maximum = *t; row = i + 1; col = t - v[i].begin() + 1; }
} cout << maximum << '\n' << row << ' ' << col;
}
사실 이 문제는 2차원 배열을 사용하지 않는 편이 더욱 간단합니다.
#include <iostream>
using namespace std;
int main() {
int max_val = -1, row, col;
for (int i = 1; i <= 9; ++i) {
for (int j = 1; j <= 9; ++j) {
int t; cin >> t; if (t > max_val) { max_val = t; row = i; col = j; }
}
} cout << max_val << '\n' << row << ' ' << col;
}
10798번 세로읽기
#include <iostream>
#include <string>
using namespace std;
int main() {
string str[5] = {}; for (int i = 0; i < 5; ++i) cin >> str[i];
for (int i = 0; i < 15; ++i) {
for (int j = 0; j < 5; ++j) {
if (i < str[j].length()) cout << str[j][i];
}
}
}
행과 열을 바꾸어 탐색합니다. 즉 바깥 반복문이 열이고 내부 반복문이 행입니다. 현재 열이 해당 행의 길이(열의 개수)보다 작다면 출력할 수 있습니다.
2563번 색종이
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
bool arr[100][100] = { 0, }; int T; cin >> T;
while (T--) {
int x, y; cin >> x >> y;
for (int i = x; i < x + 10; ++i) {
fill(arr[i] + y, arr[i] + y + 10, 1);
}
} int cnt = 0; for (int i = 0; i < 100; ++i) cnt += count(arr[i], arr[i] + 100, 1);
cout << cnt;
}
fill 함수로 입력 받은 구역을 1로 채운 뒤 count 함수로 총 1의 개수를 세었습니다.
해당 코드 채점 이후 다시 짠 코드입니다.
#include <iostream>
using namespace std;
int main() {
bool arr[100][100] = { 0, }; int T, cnt = 0; cin >> T;
while (T--) {
int x, y; cin >> x >> y;
for (int i = x; i < x + 10; ++i) {
for (int j = y; j < y + 10; ++j) {
if (!arr[i][j]) { arr[i][j] = 1; ++cnt; }
}
}
} cout << cnt;
}
구역을 채움과 동시에 카운트를 진행하는 방식입니다. 입력 이후 배열을 다시 훑는 전 코드보다 효율입니다.
그런데 전자를 왜 짰냐고 하면 fill, count 함수를 학습했다는 점에서 의미가 있다고 봅니다.
Top comments (0)