1. string를 사용 ( 매우 쉬움 )

2. 구조체 안에 char배열 선언해서 해결하는 방법 ( 쏘쏘 )

3. string + unordered_set을 이용해서 같은 문자열 필터링 ( 속도 얼마 나올지 궁금해서 해본 것 )

 

1. string

#include <bits/stdc++.h>

using namespace std;

bool compare(const string& s1, const string& s2) {
	if (s1.size() == s2.size()) return s1 < s2;
	return s1.size() < s2.size();
}

string str[20001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i) cin >> str[i];

	sort(str, str + n, compare);

	cout << str[0] << '\n';
	// 이전에 string과 같으면 출력 X
	for (int i = 1; i < n; ++i) if (str[i - 1] != str[i]) cout << str[i] << '\n';

	return 0;
}

2. 구조체 사용

#include <bits/stdc++.h>
using namespace std;

struct Word {
	// 문자열의 길이가 50을 넘지 않으므로 1Byte로도 표현 가능
	char size;
	char str[51];
};

bool compare(const Word& w1, const Word& w2) {
	if (w1.size == w2.size) for (int i = 0; i < w1.size; ++i) {
		if (w1.str[i] == w2.str[i]) continue;
		return w1.str[i] < w2.str[i];
	}
	return w1.size < w2.size;
}

Word word[20001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) {
		cin >> word[i].str;
		word[i].size = strlen(word[i].str);
	}

	sort(word, word + n, compare);

	cout << word[0].str << '\n';
	for (int i = 1; i < n; ++i) if (strcmp(word[i].str, word[i - 1].str)) cout << word[i].str << '\n';
	
	return 0;
}

이 코드는 운 좋게.. 1페이지에 등극했다..

재밌는 점은 printf를 쓰면 20ms가 나오고 cout을 쓰면 16ms가 나온다. fastio의 힘은 대단하다.

 

3. string + unordered_set

#include <bits/stdc++.h>
#include <unordered_set>
using namespace std;

bool compare(const string& s1, const string& s2) {
	if (s1.size() == s2.size()) return s1 < s2;
	return s1.size() < s2.size();
}

vector<string> vec;
unordered_set<string> us;
int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;

	string str;
    
	for (int i = 0; i < n; ++i) {
		cin >> str;
		// 이미 존재하는 문자열인지 확인, 없다면 추가 
		if (us.find(str) == us.end()) {
			us.insert(str);
			vec.push_back(str);
		}
	}

	sort(vec.begin(), vec.end(), compare);

	for (string& str : vec) cout << str << '\n';

	return 0;
}

미친듯이 느리다. 해시함수를 내가 직접 구현하면 좀 더 빠를 수도.. ??

좌표 정렬하기 1과 다르게 이번엔 y좌표를 먼저 보고 x좌표를 본다. 비교함수만 다르게 넣어주면 간단하게 해결할 수  있다.

 

1. 비교 함수 정의

#include <bits/stdc++.h>

using namespace std;

struct Pos {
	int x;
	int y;
};

bool compare(const Pos& p1, const Pos& p2){
    if(p1.y == p2.y) return p1.x < p2.x;
    return p1.y < p2.y;
}

Pos pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) cin >> pos[i].x >> pos[i].y;

	sort(pos, pos + n, compare);

	for (int i = 0; i < n; ++i) cout << pos[i].x << ' ' <<  pos[i].y << '\n';

	return 0;
}

2. operator< 정의

#include <bits/stdc++.h>

using namespace std;

struct Pos {
	int x;
	int y;

	bool operator< (Pos& p) {
		if (this->y == p.y) return this->x < p.x;
		return this->y < p.y;
	}
};

Pos pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) cin >> pos[i].x >> pos[i].y;

	sort(pos, pos + n);

	for (int i = 0; i < n; ++i) cout << pos[i].x << ' ' <<  pos[i].y << '\n';

	return 0;
}

3. Pair 클래스

#include <bits/stdc++.h>

using namespace std;

bool compare(const pair<int, int>& p1, const pair<int, int>& p2) {
	if (p1.second == p2.second) return p1.first < p2.first;
	return p1.second < p2.second;
}

pair<int, int> pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) cin >> pos[i].first >> pos[i].second;
    
	sort(pos, pos + n, compare);
    
	for (int i = 0; i < n; ++i) cout << pos[i].first << ' ' << pos[i].second << '\n';

	return 0;
}

좌표를 저장하는 구조체를 저장하고, 주어진 조건대로 정렬해줄 비교 함수를 작성하면 끝이다.

내가 정의한 구조체를 정렬할 때 비교함수를 직접 작성해도 되고 구조체 안에서 연산자 오버로딩을 해주면 된다.

 

1. 비교함수 작성

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
// 좌표를 저장한 구조체
struct Pos {
	int x;
	int y;
};
// 비교함수
bool compare(const Pos& p1, const Pos& p2) {
	if (p1.x == p2.x) return p1.y < p2.y;
	return p1.x < p2.x;
}

Pos pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
    
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) cin >> pos[i].x >> pos[i].y;

	sort(pos, pos + n, compare);

	for (int i = 0; i < n; ++i) cout << pos[i].x << ' ' << pos[i].y << '\n';

	return 0;
}


2. operator< 정의 (연산자 오버로딩)

#include <bits/stdc++.h>

using namespace std;

struct Pos {
	int x;
	int y;

	bool operator< (Pos& p) {
		if (this->x == p.x) return this->y < p.y;
		return this->x < p.x;
	}
};

Pos pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
    
	int n;
	cin >> n;

	for (int i = 0; i < n; ++i) cin >> pos[i].x >> pos[i].y;
	// operator<를 정의해주었기 때문에 따로 비교함수가 필요없다
	sort(pos, pos + n);

	for (int i = 0; i < n; ++i) cout << pos[i].x << ' ' <<  pos[i].y << '\n';

	return 0;
}


꿀팁으로 STL에서 제공하는 pair 클래스를 이용하면 굳이 구조체를 정의하지 않아도 된다. 

알고리즘 문제를 해결하다보면 자주 쓰게 되기 때문에 사용법에 익숙해지는 걸 추천드린다.

 

3. pair 클래스

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

pair<int, int> pos[100001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
    
	int n;
	cin >> n;
    
	for (int i = 0; i < n; ++i) cin >> pos[i].first >> pos[i].second;
    
	sort(pos, pos + n);
    
	for (int i = 0; i < n; ++i) cout << pos[i].first << ' ' <<  pos[i].second << '\n';
    
	return 0;
}

Pair로 선언된 배열을 정렬할 때 비교함수를 안넣게 되면

  1. first를 기준으로 오름차순으로 정렬
  2. first가 같다면 second를 기준으로 오름차순 정렬

이렇게 정렬해준다. 물론 비교 함수를 따로 작성해주어도 된다.

문제의 의도는 주어진 수를 문자열로 받아 정렬시키는 것으로 보인다...

하지만 수가 고작 10자리이기 때문에, 벡터로도 추우우웅분히 해결 가능하다.

 

1. 문자열로 입력받기

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int INF = 2147483647;
const int MAX = 10e+8;

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	string str;
	cin >> str;
    
	sort(str.begin(), str.end(), greater<char>());
    
	cout << str;
	
	return 0;
}

2. int형으로 입력받기

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int INF = 2147483647;
const int MAX = 10e+8;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }

vector<int> vec;

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int num;
	cin >> num;
    
	// 한자리씩 나누기
	while (num) {
		vec.push_back(num % 10);
		num /= 10;
	}
    
	sort(vec.begin(), vec.end(), greater<int>());
	
	for (int& i : vec) cout << i;
	
	return 0;
}

여러가지 스끼리 필요한 문제다.

 

1. 산술평균

math.h에서 제공하는 round함수를 사용하면 가볍게 소수점 첫째자리에서 반올림을 해준다.

다만, 그러기 위해서 나눗셈의 결과를 int형 변수가 아니라 double형 변수에 저장해야 원하는 결과를 얻을 수 있다. 자명하게도 int형 변수는 소수점 아랫자리가 컷트되기 때문.

 

2. 중앙값

왜 \(n\)이 항상 홀수일까 ?

프로그래밍에서 \(n\)이 홀수일 때, \(n / 2\)은 중앙을 가르키기 때문이다.

무슨 말이냐 ?

5개짜리 배열을 만들면, 인덱스가 0, 1, 2, 3, 4가 만들어진다. int형 변수에 \( 5 / 2\)를 저장하면 저장되는 값은 2.

우연히 5개짜리 배열의 중앙 인덱스 값이 나왔다.

 

7개짜리 배열을 만들어보자. 인덱스가 0, 1, 2, 3, 4, 5, 6이 만들어진다. int형 변수에 \( 7 / 2\)를 저장하면 저장되는 값은 3.

이번에도 우연히 7개짜리 배열의 중앙 인덱스 값이 나왔다.

 

사실 우연이 아니라 자명한 것이다. 이와 같은 성질은 알고리즘 문제를 해결할 때 생각보다 자주 쓰이니까 알아두면 좋다 !

따라서, 중앙값은 정렬되어있는 배열의 \(n / 2\)번째 인덱스에 저장되었는 값이 된다.

 

3. 최빈값

나오는 값의 범위가 \([-4000 , 4000]\)이니까, 어떤 수가 몇 번 나왔는지 체크하는 건 어렵지 않다.

다만, 최빈값이 여러 개라면 두번째로 작은 값을 출력해야되는 것이 까다로울 수 있다.

아이디어는 이렇다. 

  1. 사전에 어떤 수의 등장한 횟수들 중 최댓값을 저장한다.
  2. -4000 ~ 4000까지 돌면서 사전에 구한 최댓값과 같은지 확인한다.
  3. 사전에 구한 최댓값과 같은 수를 두 개째 확인하면 그대로 for문을 종료.

4. 범위

중앙값을 위해 이미 배열을 정렬한 상태라고 가정하자.

정렬되어있다면 첫번째 인덱스와 마지막 인덱스가 각각 최솟값, 최댓값임은 자명하다.

마지막 인덱스에 저장된 값에서 첫번째 인덱스에 저장된 값을 빼주자.

 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int INF = 2147483647;
const int MAX = 10e+8;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }
int num[500001];
int cnt[8001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	int n;
	double sum = 0;
	int maxCount = 0;
	cin >> n;

	for (int i = 0; i < n; ++i) {
		cin >> num[i];

		sum += num[i];
		maxCount = max(maxCount, ++cnt[num[i] + 4000]);
	}

	sort(num, num + n);

	// 산술평균
	cout << (int)round(sum / n) << '\n';

	// 중앙값
	cout << num[n / 2] << '\n';
	
	// 최빈값
	int modeValue = -4000, numOfMaxCount = 2;
	for (int i = 0; i < 8001 && numOfMaxCount; ++i) if (cnt[i] == maxCount) {
		modeValue = i - 4000;
		numOfMaxCount--;
	}
	cout << modeValue << '\n';

	// 범위
	cout << num[n - 1] - num[0] << '\n';

	return 0;
}

수 정렬하기, 수  정렬하기 2와 다르게 주어진 메모리가 8MB 밖에 없다...

만약 10,000,000개짜리 int형 배열을 선언하면, 40,000,000B = 40,000KB = 40MB 의 메모리가 필요하기 때문에 보나마나 메모리 초과다.

 

다른 조건을 이용하여 풀어야 한다. 입력 조건을 보면 10,000,000개의 수가 주어지고, 각 수는 10,000보다 크지 않은 자연수라고 한다.

첫 조건은 이미 나가리고... 10,000보다 크지 않은 수라는 점을 이용하여 해결하자.

어떻게 해결하지 생각해보니까 간단하다.

어떤 수가 몇 번 등장했는지만 안다면, 우리는 정렬할 수 있다.

 

10,001개짜리 배열 arr을 선언하자.

어떤 수를 입력받았을 때, arr[입력받은 수]에 저장된 값을 +1하자.

입력이 끝나면, for문을 통해 i를 1부터 10,000까지 돌면서 arr[i]에 저장된 값만큼 해당 수를 출력해주면 된다.

 

이와 같이 등장한 수의 개수를 이용한 정렬을 우리는 계수 정렬(Counting Sort)라고 부른다. 이 정렬은 입력 받을 수의 범위를 알아야만 사용 가능하다는 점을 잊지말자 !

#include <iostream>
using namespace std;
int arr[10001] = { 0 , };
int main() {
	ios::ios_base::sync_with_stdio(false);
	cout.tie(nullptr);
	cin.tie(nullptr);
    
	int N, tmp;
	cin >> N;
    
	for (int i = 0; i < N; i++) {
		cin >> tmp;
		arr[tmp]++;
	}
    
	for (int i = 1; i <= 10000; i++) {
		// 등장한 적이 없는 수이기 때문에 패스
		if (arr[i] == 0) continue;
        
		// 등장한 만큼 출력
		while(arr[i]--) {
			cout << i << '\n';
		}
	}

	return 0;
}

수 정렬하기 2 문제를 다시 보니, 이 문제 역시 계수 정렬로 해결가능하다 !

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int INF = 2147483647;
const int MAX = 10e+8;

ll gcd(ll a, ll b) { for (; b; a %= b, swap(a, b)); return a; }

bool isExist[2000001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	int n, tmp;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> tmp;
		isExist[tmp + 1000000] = true;
	}

	for (int i = 0; i < 2000001; ++i) if (isExist[i]) cout << i - 1000000 << '\n';
	return 0;
}

계수 정렬로 해결하니.. 58등으로 3페이지에 위치할 수 있었다.. 굿

'BOJ_단계별로 풀어보기(9단계~) > [11단계] 정렬' 카테고리의 다른 글

[백준 1427] 소트인사이드  (0) 2022.03.08
[백준 2108] 통계학  (0) 2022.03.08
[백준 2751] 수 정렬하기 2  (0) 2022.03.08
[백준 2750] 수 정렬하기  (0) 2022.03.08
C++ Sort함수  (0) 2022.03.08

2750번과 마찬가지로 sort함수를 이용하여 해결하였습니다.

#include <iostream>
#include <algorithm>
using namespace std;

int num[1000001];

int main() {
	ios::ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
    
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) cin >> num[i];
    
	sort(num, num + n);

	for (int i = 0; i < n; i++) cout << num[i] << '\n';
    
	return 0;
}

'BOJ_단계별로 풀어보기(9단계~) > [11단계] 정렬' 카테고리의 다른 글

[백준 2108] 통계학  (0) 2022.03.08
[백준 10989] 수 정렬하기 3  (0) 2022.03.08
[백준 2750] 수 정렬하기  (0) 2022.03.08
C++ Sort함수  (0) 2022.03.08
12단계에 관해서..  (0) 2022.03.04

sort함수를 이용하여 가볍게 풀이하였습니다. 

#include <iostream>
#include <algorithm>
using namespace std;

int num[1000];

int main() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) cin >> num[i];
	sort(num, num + n);

	for (int i = 0; i < n; i++) cout << num[i] << '\n';
	return 0;
}

'BOJ_단계별로 풀어보기(9단계~) > [11단계] 정렬' 카테고리의 다른 글

[백준 2108] 통계학  (0) 2022.03.08
[백준 10989] 수 정렬하기 3  (0) 2022.03.08
[백준 2751] 수 정렬하기 2  (0) 2022.03.08
C++ Sort함수  (0) 2022.03.08
12단계에 관해서..  (0) 2022.03.04

+ Recent posts