Baekjun—統計学[java]


質問元:https://www.acmicpc.net/problem/2108

問題の説明


処理数は統計学においてかなり重要なことである.統計学では、N個の数を表す基本統計値は以下のとおりである.しかし、Nは奇数であると仮定する.
算術平均:N個の数の和をNで割った値
中心値:N個の数字が順次に出たときの中央にある値.
最も頻繁な値:N個の数字の中で最も多い値を表示します
範囲:N個の数字の中で最も高い値と最も高い値の差
N個の数値が与えられた場合、4つのデフォルト統計値を求めるプログラムを作成します.
入力例
5
1
3
8
-2
2
サンプル出力
2
2
1
10

問題を解く

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

public class Main {
    public static void main(String [] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


        StringBuilder sb = new StringBuilder();
        int total = Integer.parseInt(br.readLine());
        int [] arr = new int[total];
        double avg = 0;
        for(int i = 0; i < total; i++) {
            arr[i] = Integer.parseInt(br.readLine());
            avg += arr[i];
        }
        avg /= total;
        
        //산술평균
        avg = Math.round(avg);
        int av = (int) avg;
        sb.append(av).append("\n");
        Arrays.sort(arr);
        
        //중앙값
        sb.append(arr[total / 2]).append("\n");
        
        // 최빈값 구하기
        int [] frequency = new int [4001];
        int [] negFrequency = new int [4001];
        for(int elem : arr) {
            if(elem < 0)
                negFrequency[Math.abs(elem)]++;
            else
                frequency[elem]++;
        }
        int max = 0;
        int num = 0;
        int second = num;
        for(int i = negFrequency.length - 1; i > 0; i--) {
            if(negFrequency[i] > max){
                max = negFrequency[i];
                num = -i;
                second = num;
            }
        }
        
        for(int i = 0; i < frequency.length; i++) {
            if(frequency[i] > max){
                max = frequency[i];
                num = i;
                second = num;
            }
        }

        int minusEliminatedIndex = num < 0 ? -num : num;
        if(num < 0) {
            for (int i = minusEliminatedIndex - 1; i > 0; i--) {
                if (negFrequency[i] == max) {
                    second = -i;
                    break;
                }
            }
        }

        if(second != num)
            sb.append(second).append("\n");
        else {
            int x = num < 0 ? 0 : num + 1;
            for(int i = x; i < frequency.length; i++) {
                if(frequency[i] == max){
                    second = i;
                    break;
                }
            }
            sb.append(second).append("\n");
        }
		//범위
        sb.append(Math.abs(arr[total - 1] - arr[0])).append("\n");
       System.out.println(sb);
    }
}
平均値、中央値、範囲を求めるのは難しくありませんが、最も貧しい値を求める部分は考えなければならない問題です.
私が見つけた方法.
各数字の周波数を求めるために、配列を負数と正数に設定し、周波数を記録します.
negative Frequency[4001]
positive Frequency[4001]
記録後の最適値が負の場合は、負の値の頻度を確認して繰り返し値を検索します.
indexの設定が重要です.たとえば、-10が最も頻繁な値である場合、負の周波数配列のインデックス10~1がスキャンされます.このように、負数を逆さまにスキャンし、負数を昇順にスキャンすればよい.

別の解釈

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


public class Main {
	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[] countSort = new int[8001]; // 넣은 숫자들, 최빈값
		int median = 100000; // 중앙값
		int max = Integer.MIN_VALUE; // 최소값
		int min = Integer.MAX_VALUE; // 최대값  범위
		int sum = 0;
		int range = 0;
		int count = 0;
		double avg = 0.0;
		int mode_max = 0;
		int mode_value = 10000;
		boolean flag = false;
		
		for (int i = 0; i < N; i++) {
			int input = Integer.parseInt(br.readLine());
			countSort[input + 4000]++; // 4000이 기준(==0)
			
			sum += input;
			
			if(input > max) {
				max = input;
			}
			
			if(input < min) {
				min = input;
			}
			
		}
		
		// 산술평균
		avg = Math.rint((double)sum / N);
		
		
		for (int i = min + 4000; i <= max + 4000; i++) { // counting sort는 인덱스가 값이니까
			
			if(countSort[i] > 0) {
				// 중앙값
				if(count <(N + 1) / 2) {
					count += countSort[i];
					median = i -4000;
				}
				
				// 최빈값
				// 중복이 없는 경우
				if(countSort[i] > mode_max){
					mode_max = countSort[i]; 
					mode_value = i - 4000;
					flag = true; 
							
				}
				
				// 중복되는 경우 
				else if(mode_max == countSort[i] && flag == true) {
					mode_value = i - 4000;
                    flag = false;
				}
				
				
			}
		}
		
		// 범위
		range = max + min*-1;
		
		sb.append((int)avg).append("\n");
		sb.append(median).append("\n");
		sb.append(mode_value).append("\n");
		sb.append(range).append("\n");
		
		System.out.println(sb);
		
		
	}
}
8000を頻度として並べ、4000を数値としてインデックスを見つけます.考えてみましたが、ちょっと直感的ではないので、そうしなかったほうがいい方法のようです.