[백준/C++] 2108번 통계학

2021. 2. 4. 00:44알고리즘/구현

728x90
반응형

문제: www.acmicpc.net/problem/2108

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

 

 

문제풀이

 

산술평균, 중앙값, 최빈값, 범위를 코드로 구현하는 문제였다.

 

입력되는 숫자의 절댓값이 4000 이하이므로 8001 크기의 배열을 선언하여 배열 인덱스를 이용해 문제를 풀었다. (해당 숫자의 개수 기록)

 

 

1. 산술평균

산술평균은 숫자의 개수와 인덱스에서 4000을 뺀 수의 곱을 모두 합쳐 N으로 나누었다. 이때 문제에서 요구하는 조건은 소수점 첫째 자리에서 반올림한 값이다. 때문에 N을 double형으로 형 변환한 후 round() 함수로 반올림해주었다.

 

 

2. 중앙값

숫자의 개수를 세어서 (N/2)+1 보다 커질 때의 값을 출력하였다.

 

 

3. 최빈값

  • 배열을 탐색하며 최빈값을 탐색하고 최고 빈도수(max)가 더 큰 수로 갱신되면 최빈값이 여러 개라는 논리 변수(manyMode)를 false로 초기화한다.
  • 만일 탐색 도중 현재까지의 최대 빈도수가 같은 다른 최빈값이 나타나면 논리 변수를 true로 초기화하고 두 번째로 작은 크기의 최빈값 또한 저장한다.

위의 과정을 for문 동안 반복한다.

 

 

4. 범위

배열이 0 이 아닌 최솟값과 최댓값의 차이를 출력하였다.

 

 

코드

#include <iostream>
#include <cmath>

using namespace std;

void mean(int* arr, int N){ //산술평균
    int sum=0;
    for(int i=0; i<=8000; i++){
            sum += arr[i]*(i-4000); //숫자 개수*숫자의 총합
    }
    cout<<round(sum/(double)N)<<"\n"; //반올림을 위해 double 형변환
}

void median(int* arr, int N){ //중앙값
    int cnt=0;
    for(int i=0; i<=8000; i++){
        cnt += arr[i]; //숫자 개수 세기
        if(cnt >= N/2+1){ //숫자 개수가 중간을 넘으면 출력
            cout<<i-4000<<"\n";
            return;
        }
    }
}

void mode(int* arr){
    int max = -1, tmp1= -1, tmp2= -1;
    bool manyMode;
    for(int i=8000; i>=0; i--){ //최빈값이 여러개일때 두번째로 작은 수를 구해야하므로 8000부터 시작해야함
        if(max > arr[i]) //빈도수가 모자라면 continue
            continue;

        if(max == arr[i]){ //빈도수가 현재 최대 빈도수와 같다면
            manyMode = true; //최대 빈도수가 여러개

            if(tmp1>i){ //그 숫자가 최빈값들 중 제일 작다면
                tmp2 = tmp1; //두번째 작은 수 저장
                tmp1 = i; //첫번째 작은 수 저장
            }
            else if(tmp2>i){ //그 숫자가 최빈값들 중 두번째로 작다면
                tmp2 = i; //두번째 작은 수 저장
            }
        }
        
        if(max < arr[i]){ //더 빈도수가 큰 값이 탐색된다면
            manyMode = false; //최빈값은 한개
            max = arr[i]; //최대 빈도수 갱신
            tmp1 = i; //최빈값 저장
            tmp2 = -1; //완전 초기화
        }
    }

    if(manyMode){ //최빈값이 여러개라면
        cout<<tmp2-4000<<"\n"; //두번째로 작은 값 출력
    }
    else{ //아니라면
        cout<<tmp1-4000<<"\n"; //최빈값 출력
    }
}

void range(int* arr){ //범위
    int max, min = -1;
    for(int i=0; i<=8000; i++){
        if(arr[i] != 0){ //값이 존재한다면
            max = i; //최대값은 계속 갱신(수는 계속 커지므로)
            if(min == -1) //최소값이 저장되지 않았다면
                min = i;
        }
    }
    cout<<max-min<<"\n";
}

int main(){
    ios::sync_with_stdio(false); cin.tie(NULL);

    int N;
    cin>>N;

    int arr[8001] = {0,};
    for(int i=0; i<N; i++){
        int num;
        cin>>num;
        arr[num+4000]++;
    }
    
    mean(arr, N);
    median(arr, N);
    mode(arr);
    range(arr);


    return 0;
}

 

 

결과

 

 

최빈값의 조건(여러 개일 때 두 번째로 작은 수 출력) 때문에 까다로워서

 

최빈값 함수의 구현이 정말 오래 걸렸습니다.

 

배열을 두 개를 썼다면 조금 더 쉽게 풀 수 있었을 것 같은데 왠지 배열을 두 개 쓰는 기는 싫어서 하나로만 했습니다.

 

이렇게 오래 걸릴 줄 알았으면 그냥 푸는 건데 괜한 짓을 한 것 같아요.

728x90
반응형

'알고리즘 > 구현' 카테고리의 다른 글

[백준/C++] 9375번 패션왕 신해빈  (0) 2021.02.16
[백준/C++] 11723번 집합  (0) 2021.02.04
[백준/C++] 2164번 카드2  (0) 2021.02.03
[백준/C++] 10989번 수 정렬하기 3  (0) 2021.02.03
[백준/C++] 1929번 소수 구하기  (0) 2021.02.03