백준 - JAVA/정렬

[백준] 2108번 : 통계학 _ JAVA ( 주석 설명 )

wch_s 2023. 2. 7. 16:54

1번

→ Collections.sort(ary)를 이용한 기본 통계값_산술평균, 중앙값, 최빈값, 범위 출력하기

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    //시간 복잡도 : O(n(log(n)))
    //공간 복잡도 : 입력값의 범위 만큼의 공간 필요
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //빠른 입력을 위해 버퍼를 이용해 입력을 받는다.
        StringBuilder sb = new StringBuilder(); //빠른 출력 위함

        int N = Integer.parseInt(br.readLine()); //수의 개수를 입력받는다.
        List<Integer> ary = new ArrayList<>(N); //수의 개수만큼 ArrayList 공간을 만든다.

        double average = 0; //산술평균, 반올림을 위해서 double 로 선언한다.
        int middle = 0; //중앙값
        int many = 0; //최반값(여러 개 있을 경우 두번째로 작은 값)
        int gap = 0; //범위(최댓값 - 최솟값)

        double sum = 0; //산술평균 값을 위해 입력받은 모든 정수를 더하기 위한 변수, 반올림 계산을 위해서는 sum/N 에서 한 변수는 double 이어야 한다.

        for(int i=0;i<N;++i){
            int num = Integer.parseInt(br.readLine()); //기본 통계값을 구하는데 사용되는 정수이다.
            ary.add(num); //ArrayList에 저장한다.

            sum += num; //입력받은 정수를 합한다.
        }

        Collections.sort(ary); //오름차순으로 정렬한다.




        int second = 1; //최빈값이 중복될 경우 두번째로 작은 값을 찾기 위한 변수
        int count = 1; //빈도수 변수
        int max = 0; //빈도수 갱신을 위한 변수

        many = ary.get(0); //입력하는 수가 1개밖에 없을 경우
        for(int i=0;i<N;++i){ //N까지 범위 설정 시, ary.get(i+1) 에서 배열 인덱스가 오버되기 때문에 N-1로 설정한다.
            for(int j=i;j<N-1;++j){ //i에 해당하는 수부터 빈도수를 파악한다.
                if(ary.get(j).equals(ary.get(j+1))) { //앞 뒤 value 가 같다면 그 빈도수를 count 해준다.
                    ++i; //중복된 수는 계산할 필요가 없기 때문에, 계산을 넘긴다.
                    ++count; //빈도수를 더한다.
                }
                else // 앞 뒤 value 가 틀리면 i에 해당하는 빈도수 계산을 멈추고, 최빈값 계산과정으로 넘어간다.
                    break;
            }

            if(max<count){ //더 큰 빈도수를 가진 정수가 있다면 갱신해준다.
                max = count;
                many = ary.get(i); //최빈값을 설정한다.
                second = 1; //두번째 최빈값을 찾기 위한 변수를 1로 초기화해준다.
            }
            else if(max == count && second<2){ //같은 빈도수를 가진 정수가 있다면 두번째 최빈값으로 생각한다.
                many = ary.get(i); //두번째 최빈값을 설정한다.
                ++second; // 세번째 최빈값부터는 걸러야하기 때문에 second 변수로 그 범위를 제한한다.
            }

            count = 1; //해당 정수의 빈도수 파악과 그에 따른 최빈값 갱신이 끝났면 초기값 1로 바꿔준다.
        }

        average = sum/N; //산술평균 값
        middle = ary.get(N/2); //중앙값
        gap = ary.get(N-1) - ary.get(0); //범위값

        sb.append(Math.round(average)).append('\n'); //반올림을 위해서 round 메서드를 사용한다.
        sb.append(middle).append('\n');
        sb.append(many).append('\n');
        sb.append(gap).append('\n');

        System.out.println(sb); //기본 통계값을 모두 출력한다.
    }
}

 


 

2번

→ Counting 정렬을 이용한 기본 통계값 출력하기

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    //시간 복잡도 : O(n(log(n)))
    //공간 복잡도 : 입력값의 범위 만큼의 공간 필요
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //빠른 입력을 위해 버퍼를 이용해 입력을 받는다.
        StringBuilder sb = new StringBuilder(); //빠른 출력 위함

        int N = Integer.parseInt(br.readLine()); //수의 개수를 입력받는다.

        int range = 4000; //입력되는 정수값의 범위 num<=|4000|
        int[] ary = new int[range*2+1]; //음수도 포함해야 하므로 range*2+1 용량의 배열을 선언한다.
        int[] sort_ary = new int[N]; //정렬된 배열은 수의 개수만큼만 필요하므로 N 용량으로 선언한다.

        int average = 0; //산술평균
        int middle = 0; //중앙값
        int many = 0; //최반값(여러 개 있을 경우 두번째로 작은 값)
        int gap = 0; //범위(최댓값 - 최솟값)

        double sum = 0; //산술평균 값을 위해 입력받은 모든 정수를 더하기 위한 변수, 반올림 계산을 위해서는 sum/N 에서 한 변수는 double 이어야 한다.

        for(int i=0;i<N;++i){
            int num = Integer.parseInt(br.readLine());
            ++ary[num+range]; //입력값의 범위에 음수도 있으므로 중심 range 을 더한다. => ary[range] 인덱스는 '0'을 의미한다.

            sum += num; //산술평균 계산을 위해 sum을 구한다.
        }

        int k = 0; //sort_ary 배열에 저장하기 위한 인덱스 변수이다.
        int max = -1; //최빈값 i를 찾기 위함으로, 수의 갯수를 의미하는 변수이다.
        boolean second = false; //최빈값이 여러개 있을 때 두번째로 작은 최빈값을 찾기 위한 변수이다.
        for(int i=0;i<ary.length;++i){ //입력되는 정수값의
            if(max<ary[i]) { //더 큰 최빈값이 있을 때
                max = ary[i]; //최빈값의 빈도 수를 갱신한다.
                many = i-range; //실제 의미하는 num을 최빈값으로 설정한다.
                second = true; //두번째로 작은 최빈값을 구하기 위해 true 로 설정한다.
            }
            else if(max==ary[i] && second == true){
                many = i-range; //두번째로 작은 최빈값으로 최빈값을 갱신한다.
                second = false; //이 후 동일한 빈도의 최빈값은 무시하도록 한다.
            }

            while(ary[i]>=1){ //중복된 수까지 전부 저장한다.
                sort_ary[k] = i-range; //sort_ary 에 정렬된 값 저장한다.
                ++k; //sort_ary에 저장할 인덱스 +1 한다.
                --ary[i]; //중복된 값 줄인다.
            }
        }

        average = (int)Math.round(sum/N); //소수점 첫째자리에서 반올림한 산술평균
        middle = sort_ary[N/2];
        gap = sort_ary[N-1]-sort_ary[0];
        
        sb.append(average).append('\n'); //산술평균
        sb.append(middle).append('\n'); //중앙값
        sb.append(many).append('\n'); //최빈값
        sb.append(gap); //범위

        System.out.println(sb); //네가지 기본 통계값 출력
    }
}

 

 

 


 

 

* 짚고 넘어가자!

1> '=='  vs 'a.equals(b)'

==
- 주소 비교
- 원시 타입 비교
- Integer 객체에서는 -128~127까지만 == 으로 비교 가능하다.

a.equals(b)
- 값 비교
- 객체 타입 비교
- Integer 객체에서는 equals 로 비교해야 한다!

 

2> 정수 나눗셈하기

- 유의하기
Math.round()

int num = Math.round(11/3);
1> (11/3) : 몫만 계산하고 나머지는 버린다.
2> 3에서 반올림을 하므로 3이 리턴된다.

int num2 = (int) Math.round(11.0/3);
1> (11.0/3) : 계산 결과가 3.66..으로 나온다.
2> 3.66에서 반올림을 하므로 4로 리턴된다.