[BAEKJOON 2908번 : 상수]
[문제]

[고찰]
아래의 코드는 제가 이 문제를 풀었을 때의 답안입니다.
저는 문자열 스트림을 통해 풀었습니다만, stoi 함수를 사용하는 방안 또한 알게되어 정리하고자 합니다.
#include <iostream>
#include <algorithm>
#include <sstream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
string x, y;
int rx, ry;
cin >> x >> y;
reverse(x.begin(), x.end());
reverse(y.begin(), y.end());
stringstream ss_x(x);
ss_x >> rx;
stringstream ss_y(y);
ss_y >> ry;
if (rx > ry)
cout << rx;
else
cout << ry;
return 0;
}
[개념]
[stoi 함수]
- 역할
- std::stoi 함수는 std::string 타입의 문자열을 int 타입의 정수 값으로 변환하는 C+11 표준부터 추가된 함수입니다.
- 문자열의 내용이 정수 형태여야 하며, 변환 과정에서 앞, 뒤의 공백 문자를 자동으로 건너뛰는 기능도 있습니다.
- 헤더파일
- <string>
- 함수 오버로드
- int stoi (const std::string& str, std::size_t* idx = nullptr, int base = 10);
- int stoi (const std::wstring& str, std:size_t* idx = nullptr, int base = 10); // wstring 버전
- const std::string& str
- 변환할 대상이 되는 입력 문자열입니다. const&로 전달되어 원본 문자열을 변경하지 않고 접근합니다.
- std::size_t* idx = nullptr
- 선택적 매개변수입니다. 만약 nullptr이 아닌 size_t 타입 변수의 주소를 전달하면, 함수는 문자열에서 숫자가 아닌 첫 번째 문자의 인덱스를 이 변수에 저장합니다. 이를 통해 문자열의 어느 부분까지 숫자로 변환되었는지 확인할 수 있습니다.
- int base = 10
- 선택적 매개변수입니다. 변환할 숫자가 어떤 진법으로 표현되었는지 지정합니다.
- const std::string& str
- 반환값
- 반환에 성공하면, 문자열 내용에 해당하는 정수(int) 값을 반환합니다.
- 오류 처리
- std::stoi는 변환 과정에서 문제가 발생하면 예외를 발생시킵니다.
- 주요 예외
- std::invalid_argument : 문자열에 유효한 숫자가 포함되어 있지 않은 경우 발생합니다.
- std::out_of_range : 문자열 내용이 유효한 숫자 형태지만,
int 타입으로 표현할 수 있는 범위를 벗어나는 경우 발생합니다.
[reverse 함수]
추가적으로 코드에서 활용된 reverse 함수를 헤더파일을 사용하지 않아 한 번 틀렸었습니다.
기존 '코딩테스트 9일차' 글에도 정리되어 있지만, 정확히 알고자 다시 한번 자세히 정리해둡니다.
- 역할
- std::reverse 함수는 주어진 반복자 범위 안의 요소들의 순서를 반대로 뒤집습니다.
- 헤더파일
- <alogorithm>
- 함수 원형
- template <class BidirecionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last);- BidirectionalIterator
- 반복자의 카테고리 중 하나입니다. std::reverse는 순방향과 역방향으로 모두 이동할 수 있는 양방향 반복자를 요구합니다.
- std::vector, std::list, std::deque와 같은 대부분의 표준 컨테이너가 제공하는 반복자는 양방향 반복자 이상의 기능을 제공하므로 std::reverse에 사용할 수 있습니다. 배열의 포인터도 양방향 반복자로 동작합니다.
- first : 뒤집기 시작할 범위의 시작을 가리키는 반복자입니다. 이 위치에 있는 요소부터 뒤집기 대상에 포함됩니다.
- last : 뒤집기 끝의 바로 다음 위치를 가리키는 반복자입니다. 이 위치에 있는 요소는 뒤집기 대상에 포함되지 않습니다.
- BidirectionalIterator
- template <class BidirecionalIterator>
- 반환값
- std::reverse 함수는 void 타입으로, 아무것도 반환하지 않습니다. 범위 내의 요소들의 순서를 직접 변경하는 역할을 수행합니다.
- 작동 방식
- std::reverse는 기본적으로 first와 last - 1에 있는 요소를 교환하고, ++first와 --last를 반복하여 중간으로 이동하면서 요소들을 쌍으로 교환합니다. first가 last를 만나거나 지나칠 때까지 이 과정을 반복합니다.
// 코드로 표현한 std::reverse 함수의 대략적 구현
while (first != last && first != --last)
{
std::swap(*first, *last);
++first;
}
- 특징
- 별도의 추가 메모리 공간을 사용하지 않고 주어진 범위 내에서 요소들의 위치만 변경하여 순서들을 뒤집습니다.
- 요소들의 순서를 뒤집기 위해 내부적으로 std::swap 연산을 사용합니다. 따라서 범위 내의 요소들은 서로 교환될 수 있어야 합니다. 대부분의 기본 제공 타입과 복사 생성자 및 대입 연산자가 잘 정의된 사용자 정의 타입은 기본적으로 교환 가능합니다.
[정리]
기존에 정리해두었던 것도 제대로 복습하지 않았다면 소용이 없다는 것을 제대로 체험한 것 같습니다.
더욱 복습하는 시간을 늘려야겠습니다.
[Solution]
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
string x, y;
int rx, ry;
cin >> x >> y
reverse(x.begin(), x.end());
reverse(y.begin(), y.end());
rx = stoi(x);
ry = stoi(y);
cout << (rx > ry ? x : y);
return 0;
}
[BAEKJOON 2798번 : 블랙잭]
[문제]

[고찰]
아래의 코드는 제가 해당 문제를 푼 답변 코드입니다만, 우연찮게 정답에 요구하는 입력값에 대해 올바른 출력이 되어 정답 처리가 된 코드인 것 같습니다.
문제를 풀면서 적용한 아이디어는, 카드들을 정렬시킨 뒤 가장 큰 값을 기준으로, 작은 값들을 차례대로 비교하는 것이었습니다.
다만, 다시 리뷰해보면서 해당 코드로는 가장 작은 세 값끼리는 합할 수 없는 치명적인 논리 오류가 있었습니다.
예제 입력을 과신하고, 나름대로 입력 값을 만들면서도 작은 값들끼리만 합해도 될 상황을 생각하지 못한 것입니다.
또한 굳이 벡터를 정렬하여서 시간 복잡도를 늘어나게 했다는 것도 문제였습니다.
나름대로 최대한 효율적인 루트를 짜본 것이었는데, 접근 방법이 잘못되었습니다.
그래서 이에 다시 올바르게 문제를 푼 내용에 대해 정리하고자 합니다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int cardNum, baseValue;
int maxValue = 0;
vector<int> cards;
cin >> cardNum >> baseValue;
while (cardNum--)
{
int x;
cin >> x;
cards.push_back(x);
}
sort(cards.begin(), cards.end());
for (int i = cards.size() - 1; i >= 0; i--)
{
for (int j = 0; j < i - 1; j++)
{
for (int k = j + 1; k <= i - 1; k++)
{
int value = cards[i] + cards[j] + cards[k];
if (value <= baseValue && value > maxValue)
{
maxValue = value;
}
}
}
}
cout << maxValue;
return 0;
}
[개념]
이번에는 벡터를 정렬하지 않고, 모든 카드를 탐색하게끔 구현을 해 보았습니다.
첫 번째 카드를 선택하는 루프는 0부터 cardNum - 2까지 반복합니다.
두 번째 카드를 선택하는 루프는 첫 번째 루프의 시작 카드의 다음부터 cardNum -1까지 반복합니다.
세 번째 카드를 선택하는 루프 역시, 두 번째 루프의 시작 카드의 다음부터 cardNum까지 반복합니다.
for (int i = 0; i < cardNum - 2; i++)
{
for (int j = i + 1; j < cardNum - 1; j++)
{
for (int k = j + 1; k < cardNum; k++)
{
int currentValue = cards[i] + cards[j] + cards[k];
// ...
}
}
}
이렇게 중첩 루프문을 구성했을 경우, cardNum이 5이고 벡터가 1부터 5까지의 값을 가진다고 했을 때, 다음의 상황들을 확인할 수 있습니다.
| card [ i ] | card [ j ] | card [ k ] |
| 1 | 2 | 3 |
| 4 | ||
| 5 | ||
| 3 | 4 | |
| 5 | ||
| 4 | 5 | |
| 2 | 3 | 4 |
| 5 | ||
| 4 | 5 | |
| 3 | 4 | 5 |
[정리]
예제 입력만을 과신하는 일이 없어야 하는데, 여러번 실수를 하게 되는 것 같습니다. 더욱 더 예제 입력만을 과신하지 말고, 다양한 상황까지 커버할 수 있게끔 상황을 가정하고 문제를 풀어야겠습니다.
뿐만 아니라, 풀이를 할 때 정립한 논리를 한 번더 확인하는 습관을 들여야겠습니다.
[Solution]
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int cardNum, baseValue;
int maxValue = 0;
cin >> cardNum >> baseValue;
vector<int> cards(cardNum);
for (int i = 0; i < cardNum; i++)
{
cin >> cards[i];
}
for (int i = 0; i < cardNum - 2; i++)
{
for (int j = i + 1; j < cardNum - 1; j++)
{
for (int k = j + 1; k < cardNum; k++)
{
int currentValue = cards[i] + cards[j] + cards[k];
if (currentValue <= baseValue)
maxValue = max(maxValue, currentValue)
}
}
}
cout << maxValue;
return 0;
}'코딩 테스트' 카테고리의 다른 글
| [코딩테스트 20일차] BAEKJOON 2231번 : 분해합 (0) | 2025.05.23 |
|---|---|
| [코딩테스트 19일차] BAEKJOON 2292번 : 벌집 (0) | 2025.05.17 |
| [코딩테스트 17일차] BAEKJOON 1052번, 10809번 (0) | 2025.05.12 |
| [코딩테스트 16일차] BAEKJOON 3052번 : 나머지 (0) | 2025.05.10 |
| [코딩테스트 15일차] BAEKJOON 5073번, 5597번 (0) | 2025.05.06 |