문제
수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.
- 산술평균 : N개의 수들의 합을 N으로 나눈 값
- 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
- 최빈값 : N개의 수들 중 가장 많이 나타나는 값
- 범위 : N개의 수들 중 최댓값과 최솟값의 차이
N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.
첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.
첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.
둘째 줄에는 중앙값을 출력한다.
셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.
넷째 줄에는 범위를 출력한다.
입력
5
1
3
8
-2
2
출력
2
2
1
10
풀이
일단 문제에서는 총 4개의 값을 원하고 있다. 정렬을 한다면 2번과 4번은 간단하게 해결 할 수 있고 1번은 평범하게 평균을 구하면 되지만 문제는 3번의 최빈값이다.
일단 처음에는 정렬문제이기도하고 최소값, 최대값을 필요로 하길래 vector에 숫자들을 넣어 정렬을 먼저했다.
1번은 round를 통해서 반올림 처리
2번은 배열크기/2+1
4번은 배열 마지막 값 - 배열 첫 번째 값
으로 풀이를 했다.
문제는 3번인데 일단 문제에서 주어진 '절댓값은 4000을 넘기지 않는다.'에서 4000까지는 그냥 일반 수를 넣고 4001부터는 음수를 넣는 방식으로 코드를 짰다.
만약 0보다 작다면 -1을 곱하고 4001을 더 했다. 4000, 4001, 8000, 8001인데 지금 생각해보면 4000을 했어도 괜찮았을 것 같지만 일단 4001을 더했다.
그렇게되면 0 ~ 4000은 양수고 4002 ~ 8001은 음수이다. (중간 4001은 그냥 없는 셈...) 이 상태에서 중간중간 배열의 인덱스와 본래 수의 변환을 하면서 빈도수를 계산하고 이 빈도수를 기준으로 최빈값을 구하였다. 개인적으로 이 3번이 완전 순수하게 아이디어를 짜내서 코드를 짜내야되서 조금 힘들었다.
그리고 문제가 하나 더 있는데 두 번째로 작은 값을 구하는 것이다. 이것도 정렬 덕분에 그나마 추가적으로 코드가 붙지 않았고 bool을 이용해서 빈도수가 같은 경우 bool이 true면 최빈값을 바꾸고 bool값을 second로 만약 보다 빈도수가 높은 값을 만나면 bool을 true로 바꾸고를 반복하면서 두 번째 값을 구하였다.
코드
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main(void){
int n, temp_array[8002] = {0, };
scanf("%d", &n);
vector<int> v;
for(int i = 0 ; i < n ; i++){//1. 배열 초기화
int temp;
scanf("%d", &temp);
v.push_back(temp);
if(temp < 0){
temp = (temp * -1) + 4001;
}
temp_array[temp]++;
}
sort(v.begin(),v.end(), less<int>());
//산술 평균
int avg;
int size = v.size(), sum = 0;
for(int i : v){
sum += i;
}
avg = round((double)sum/size);
printf("%d\n", avg);
//중간 값
int middle = size/2+1;
printf("%d\n", v[middle-1]);
//최빈 값
int max_cnt = 0, max = 0;
int check = 0;
bool second = true;
for(int i : v){
if(i < 0){
i = (i * -1) + 4001;
}
if(max_cnt < temp_array[i]){
max_cnt = temp_array[i];
max = i;
second = true;
}
else if(max_cnt == temp_array[i] && second == true && max != i){
max = i;
second = false;
}
check++;
}
if(max > 4000){
max = (max - 4001) * -1;
}
printf("%d\n", max);
//차이
printf("%d\n", v[size-1] - v[0]);
}
크게 더 보충할 내용은 없고
1. 문제를 읽고
2. 문제를 파악하고
3. 문제를 푼다.
의 3단계를 아주 잘 사용한 것 같다.
한 번에 통과 했더니 확실히 기분이 좋다. 아니었으면 뭐가 잘못 된건지 찾느라 시간을 오래쓰지 않았을까?
'공부 > C++' 카테고리의 다른 글
[C/C++] 좌표 정렬하기 (백준 11650) (0) | 2020.08.19 |
---|---|
[C/C++] 소트인사이드 (백준 1427) (0) | 2020.08.19 |
[C/C++] 수 정렬하기 3 (백준 10989) (0) | 2020.08.18 |
[C/C++] 수 정렬하기 2 (백준 2751) (0) | 2020.08.18 |
[C/C++] 영화감독 숌 (백준 1436) (0) | 2020.08.14 |