DEV Community

dbsans
dbsans

Posted on

[BOJ/C, C++] 단계별로 풀어보기 문자열 ~ 2차원 배열

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;
}
Enter fullscreen mode Exit fullscreen mode

가장 기본적인 방법입니다. 문자 '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);
}
Enter fullscreen mode Exit fullscreen mode

%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;
}
Enter fullscreen mode Exit fullscreen mode

처음에는 if 조건을 아래처럼 작성하였습니다.

i != 0 && i != str.length() - 1 && str[i] == ' '
Enter fullscreen mode Exit fullscreen mode

이렇게 하니 공백만 입력된 경우를 걸러낼 수 없어 연산이 진행되지 않은 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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

저는 find 메서드를 사용하여 풀었습니다. 해당하는 문자가 없을 때 false를 반환하는 게 아니라 string::npos를 반환하기 때문에 위와 같이 작성해야 합니다.
하지만

int num_pad[26] = {3, 3, 3, 4, 4, 4, ...};
// ...
for (int c : T) n += num_pad[c - 'A'];
Enter fullscreen mode Exit fullscreen mode

중첩반복문을 사용하지 않는 아래 코드가 더 좋은 것 같습니다.

11718번 그대로 출력하기

EOF를 사용한 문제입니다. 어제 배운 게 생각나서 응용해서 풀어보았습니다.

#include <iostream>
#include <string>
using namespace std;
int main() {
    string str; while (getline(cin, str)) cout << str << '\n';
}
Enter fullscreen mode Exit fullscreen mode

입력 내에 공백이 입력될 수 있는 것을 간과하고 cin을 사용했다가 오답 처리 되었습니다. getlinecin을 리턴하기 때문에 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');
}
Enter fullscreen mode Exit fullscreen mode

아스키코드를 이용하여 풀었습니다. 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();
}
Enter fullscreen mode Exit fullscreen mode

크로아티아 문자를 찾아 *로 치환한 후 문자열 길이를 출력합니다.

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;
}
Enter fullscreen mode Exit fullscreen mode

새로 등장한 문자이거나 현재 그 문자가 아니면 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;
}
Enter fullscreen mode Exit fullscreen mode

사실 이 문제는 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;
}
Enter fullscreen mode Exit fullscreen mode

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];
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

행과 열을 바꾸어 탐색합니다. 즉 바깥 반복문이 열이고 내부 반복문이 행입니다. 현재 열이 해당 행의 길이(열의 개수)보다 작다면 출력할 수 있습니다.

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

구역을 채움과 동시에 카운트를 진행하는 방식입니다. 입력 이후 배열을 다시 훑는 전 코드보다 효율입니다.
그런데 전자를 왜 짰냐고 하면 fill, count 함수를 학습했다는 점에서 의미가 있다고 봅니다.

Top comments (0)