이번 문제는 여지껏 배웠던 C++ 지식을 최대한 활용하여 풀어봤다.
우선은, 기존 main에 다 때려박았던 걸 조금 분리 해볼 생각이었다.
#pragma once
#define interface struct
__interface ISol
{
virtual void Solution() = 0;
virtual void Intput() = 0;
virtual void Solved() = 0;
};
ISOl 인터페이스를 하나 만들어줬고
#pragma once
#include "ISol.h"
class Sol: public ISol
{
void Solution() override;
void Intput() override;
void Solved() override;
};
해당 ISOL 인터페이스를 상속 받도록 Sol Class를 만들어주었다. 구현부는 Sol.cpp에 구현하도록 설계 하였다.
#include <iostream>
#include "Sol.h"
#include "ISol.h"
#include <memory>
using namespace std;
int main() {
unique_ptr<ISol> solved = make_unique<Sol>();
solved->Solved();
}
메인에선 단순히 ISol 인터페이스를 스마트 포인터를 통해 생성해주었는데 main은 현재 추상화(ISol)과 구현부(Sol) 두 개를 모두 의존하고 있기 때문에, SOLID 법칙에 위배되지만, Appconfig와 같은 설정 Class를 만들어주거나, DI를 통해
의존 관계를 느슨하게 설계해줄 순 있지만 우선은 위와 같이 설계 하였다.
#include "Sol.h"
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define MAX 500'001
int N;
int arr[MAX];
using namespace std;
void Sol::Intput()
{
cin >> N;
for (int i = 0; i < N; i++)
{
cin >> arr[i];
}
}
int Sol1() {
int sum = 0;
for (int i = 0; i < N; i++)
{
sum += arr[i];
}
return round(static_cast<double>(sum) / N);
}
int Sol2() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v[N / 2];
}
int Sol3() {
map<int, int> m;
for (int i = 0; i < N; i++)
{
if (m.find(arr[i]) == m.end())
{
m.insert({ arr[i],1 });
}
else m[arr[i]]++;
}
vector<int> modeValues;
int maxFrequency = 0;
for (const auto& entry : m) {
if (entry.second > maxFrequency) {
maxFrequency = entry.second;
modeValues = { entry.first };
}
else if (entry.second == maxFrequency) {
modeValues.push_back(entry.first);
}
}
if (modeValues.size() < 2) {
return modeValues[0];
}
sort(modeValues.begin(), modeValues.end());
return modeValues[1];
}
int Sol4() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v.back() - *v.begin();
}
void Sol::Solution()
{
cout << Sol1() << endl;
cout << Sol2() << endl;
cout << Sol3() << endl;
cout << Sol4() << endl;
}
void Sol::Solved() {
Intput();
Solution();
}
전체적인 코드는 위와 같은데 하나하나 설명 해보고자 한다. 차후 Code를 제출하기 위해선 위 코드를
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#define MAX 500'001
int N;
int arr[MAX];
using namespace std;
void Intput()
{
cin >> N;
for (int i = 0; i < N; i++)
{
cin >> arr[i];
}
}
int Sol1() {
int sum = 0;
for (int i = 0; i < N; i++)
{
sum += arr[i];
}
return round(static_cast<double>(sum)/N);
}
int Sol2() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v[N / 2];
}
int Sol3() {
map<int, int> m;
for (int i = 0; i < N; i++)
{
if (m.find(arr[i]) == m.end())
{
m.insert({ arr[i],1 });
}
else m[arr[i]]++;
}
vector<int> modeValues;
int maxFrequency = 0;
for (const auto& entry : m) {
if (entry.second > maxFrequency) {
maxFrequency = entry.second;
modeValues = { entry.first };
}
else if (entry.second == maxFrequency) {
modeValues.push_back(entry.first);
}
}
if (modeValues.size() < 2) {
return modeValues[0];
}
sort(modeValues.begin(), modeValues.end());
return modeValues[1];
}
int Sol4() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v.back() - *v.begin();
}
void Solution()
{
cout << Sol1() << endl;
cout << Sol2() << endl;
cout << Sol3() << endl;
cout << Sol4() << endl;
}
void Solved() {
Intput();
Solution();
}
int main() {
Solved();
}
위 코드로 다시 수정하긴 했지만, 중요한 건 그동안 배웠던 걸 잘 활용했었냐를 좀 중요시했다.
int Sol1() {
int sum = 0;
for (int i = 0; i < N; i++)
{
sum += arr[i];
}
return round(static_cast<double>(sum) / N);
}
Sol1 함수에선 산술 평균을 내는 것이며 N개의 수의 합을 N개로 나눈 값이다. 단, 반올림 까지 생각해야 하므로 여기선
round를 사용하였으며, round를 할 때 sum이 int 값이면 뒤에 소수 값이 나오지 않기 때문에 double로 캐스팅 해주었다.
int Sol2() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v[N / 2];
}
Sol2 함수에선 하나의 벡터를 선언하고 copy_n을 통해, N개 만큼 벡터에 복사해주었다. 단 back_inserter를 넣지 않고 그대로 벡터를 넣으면 크래쉬가 났었고. 벡터에 배열을 복사하기 위해선 위와 같은 작업이 필요했다.
이후 sort 함수를 통해 정렬 후,N/2 만큼 인덱스 접근으로 중앙 값을 찾아내었다.
int Sol3() {
map<int, int> m;
for (int i = 0; i < N; i++)
{
if (m.find(arr[i]) == m.end())
{
m.insert({ arr[i],1 });
}
else m[arr[i]]++;
}
vector<int> modeValues;
int maxFrequency = 0;
for (const auto& entry : m) {
if (entry.second > maxFrequency) {
maxFrequency = entry.second;
modeValues = { entry.first };
}
else if (entry.second == maxFrequency) {
modeValues.push_back(entry.first);
}
}
if (modeValues.size() < 2) {
return modeValues[0];
}
sort(modeValues.begin(), modeValues.end());
return modeValues[1];
}
솔직히 가장 해맸던 부분. 최빈값을 구하고 그 중 2번 째로 작은 수를 구하는 문제였는데 이 부분의 경우, 문제에서 입력될 수 있는 값이 절대값 4000을 넘지 않는다 즉 (-4000 ~ 4000 ) 까지의 수를 입력받으니 8001개의 배열을 만들어 두는 방법도 있었지만, 필자는 위와 같은 문제에선 map을 사용하는 것을 선호했기에 map을 어떻게든 사용해보고자 하였다.
풀이를 하자면 map에 arr[i]를 find를 통해 찾아보고 없다면 insert 있다면 1씩 증가 시켜주었다.
이후 sort를 하기 위해서 따로 vector를 만들고 size를 체크해서 2보다 작다면 벡터의 0 번째 인덱스의 값을
아니라면 인덱스의 1번째 값을 리턴해주었다.
int Sol4() {
vector<int> v;
copy_n(arr, N, back_inserter(v));
sort(v.begin(), v.end());
return v.back() - *v.begin();
}
마지막으로 Sol4의 경우 최소값과 최대값의 차이를 출력하는 문제인데.
벡터의 back 함수를 통해 마지막 값(최대값)과 v.begin()의 포인터를 통해 최소값을 가져와 둘을 뺄샘 한 값을 출력해주었다. 물론 v.begin() 이 아닌 v.front()를 써도 된다.

'프로그래밍-기본기 > 알고리즘(문제풀이)' 카테고리의 다른 글
| (백준) 2839 설탕 배달 c++ 그리디 알고리즘 (0) | 2023.09.19 |
|---|---|
| (백준) 2775 부녀회장이 될테야 C++ (0) | 2023.09.18 |
| (백준) 1874 스택 수열 C++ (0) | 2023.09.11 |
| (백준) 1676 팩토리얼 0의 개수 C# (2) | 2023.09.08 |
| [백준] 1654 랜선 자르기 -C++ (0) | 2023.09.07 |