Baekjoon algorithm training

[백준] 2108 (통계학)

interfacer_han 2023. 12. 15. 17:15

#1 알고리즘

한 번의 for문으로 모든 걸 다 구하고 싶었다, 그 편이 성능에서 더 좋을 것이라는 생각에서였다. 하지만, 코드가 심각하게 길어지거나 코드가 짧은 대신 가독성이 좋지 않았다. 그래서 for문을 2번 쓰는 코드를 짰다. 첫번째 for문은 N개의 수를 읽어, 배열 valueCounts를 완성한다. 두번째 for문에선 완성된 배열 valueCounts를 순회하며 산술평균, 중앙값, 최빈값, 범위를 도출한다.

 

#2 코드 - 코틀린

import java.util.Queue
import java.util.LinkedList
import kotlin.math.roundToInt

/*
(1) 산술평균: Arithmetic mean
(2) 중앙값: Median
(3) 최빈값: Mode
(4) 범위: Range
*/
fun main() {
    val N = readln().toInt()
    /*
    수의 범위: (-4000 ~ 4000)
    이 범위에 +4000 하면 (0 ~ 8000)
    (0 ~ 8000) 라는 범위는 배열의 인덱스로 쓰기에 적합하다
    */
    val valueCounts : Array<Int> = Array(8001) { 0 }

    // N개의 수 순회
    for(i : Int in 0..<N) {
        valueCounts[readln().toInt() + 4000]++
    }

    // 여러가지 변수들 선언
    var order = 0 // 순서 기록용 변수
    var sum : Double = 0.0 // for (1) 산술평균
    var median = 0 // for (2) 중앙값
    val orderOfMedian = (N / 2) + 1 // for (2) 중앙값
    var modeCount = 0 // for (3) 최빈값
    val modes : Queue<Int> = LinkedList() // for (3) 최빈값
    var min = 0 // for (4) 범위
    var max = 0 // for (4) 범위

    // valueCounts 순회 (0부터 8000까지)
    for(value : Int in 0..<valueCounts.size) {

        if(valueCounts[value] == 0) {
            continue
        }

        // (1) 산술평균 (순서 기록과 관계없는 변수이기때문에, 제일 앞에 둔다.)
        sum += value * valueCounts[value] // "* valueCounts[value]"를 빼먹지 않게 주의해야 한다.

        if(order == 0) { // N이 1인 경우를 위한 if문
            // 순서 기록
            order += valueCounts[value]

            // (2) 중앙값
            median = value

            // (3) 최빈값
            modeCount = valueCounts[value]
            modes.offer(value)

            // (4) 범위
            min = value
            max = value

            continue
        }

        // (2) 중앙값 (이전 반복의 order 값이 필요하기 때문에, '순서 기록'보다 더 앞에 둠)
        median = if((order < orderOfMedian) && (orderOfMedian <= order + valueCounts[value])) {value} else {median}

        // 순서 기록
        order += valueCounts[value]

        // (3) 최빈값
        if(modeCount == valueCounts[value]) {
            modes.offer(value)

        } else if(modeCount < valueCounts[value]) {
            modeCount = valueCounts[value]
            modes.clear()
            modes.offer(value)
        }

        // (4) 범위
        min = if(value < min) {value} else {min}
        max = if(max < value) {value} else {max}
    }

    // valueCounts 순회는 오름차순이었기 때문에, modes 담긴 값들은 늦게 들어온 값일수록 더 큰 수일 것이다.
    val mode : Int = if(modes.size == 1) {modes.peek()} else {modes.poll(); modes.peek()}

    // 반올림 작업
    val arithmeticMeanToSubmit = ((sum - 4000 * N) / N).roundToInt()

    print("${arithmeticMeanToSubmit}\n${median - 4000}\n${mode - 4000}\n${max - min}\n")
}

'Baekjoon algorithm training' 카테고리의 다른 글

[백준] 1920 (수 찾기)  (0) 2023.12.25
[백준] 11723 (집합)  (0) 2023.12.21
[백준] 10845 (큐)  (0) 2023.12.14
[백준] 28417 (스케이트보드)  (0) 2023.12.11
[백준] 11866 (요세푸스 문제 0)  (0) 2023.12.09