데블 아니고 데블리

운동,햄버거, 개발 좋아요

🐷💻📝

항해99 취업 리부트 코스 학습일지

[항해99 취업 리부트 코스 학습일지] 2024.04.06(토)

데블아니고데블리 2024. 4. 8. 08:53

오늘은 기존에 배웠던 개념을 복습했던 날인 것 같다

3번 문제에서 많이 어려움을 느꼈다...

 

옆으로도 돌려보고 찢어도 보고 했는데, 결국 좌표로 구해서 풀었다.

클래스도 만들어 보긴 했으나 자꾸 실패가 떠서 어려웠다

=========================================================================

풀었던 문제

[백준 2108번 통계학]

https://www.acmicpc.net/problem/2108

 

2108번: 통계학

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

www.acmicpc.net

package src.com.company.week2.day4;

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

/**
 * 메모리 : 64540KB, 시간 840ms
 *
 * */
public class BJ_2108_통계학 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        int[] numArray = new int[N];

        int sum = 0;
        int midIndex = N / 2;

        //최빈값 구하기 위한 맵
        Map<Integer, Integer> map = new TreeMap<>();

        for(int i = 0; i < N; i++) {
            // 값 넣으면서
            numArray[i] = Integer.parseInt(br.readLine());
            // 산술평균에 필요한 합 구하고
            sum += numArray[i];
            // 최빈값 구하는 맵에도 넣고(키: 배열요소, 값: 빈도수)
            map.put(numArray[i],map.getOrDefault(numArray[i],0) + 1);
        }
        // 오름차순 정렬
        Arrays.sort(numArray);

        //1. 산술평균 : 은근.. 자료형이 어려웠습니다.
        int average = calculateAverage(sum, N);
        System.out.println(average);
        //2. 중앙값
        int median = numArray[midIndex];
        System.out.println(median);
        //3. 최빈값
        int frequency = calculateFrequency(map);
        System.out.println(frequency);
        //4. 범위
        int range = Math.abs(numArray[N-1] - numArray[0]);
        //int range2 = numArray[N-1] - numArray[0];
        System.out.println(range);

    }

    public static int calculateAverage(int sum, int N) {

        double doubleAverage = (double) sum / N;
        if(doubleAverage < 0) {
            // 여기서 애먹었다.. 음수 양수로 만들고(절댓값) 다시 음수 만들고 반올림(round) 해줘야 함
            return (int) Math.round(Math.abs(doubleAverage) * -1);
        } else {
            return (int) Math.round(doubleAverage);
        }
    }

    public static int calculateFrequency(Map<Integer, Integer> map) {
        //(키: 배열요소, 값: 빈도수) 인 맵 : 빈도수 큰 것부터 정렬

        int freq = Collections.max(map.values());
        // 최빈값 배열
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            //해당 value값이 maxValue값과 같으면 또 최빈값이 있는거니까 키값(원래의 값 넣어주기)
            if (entry.getValue() == freq) {
                arrayList.add(entry.getKey());
            }
        }

        // 두번째 작은 값 구하기
        if(arrayList.size() > 1) {
            return arrayList.get(1);
        }
        else {
            return arrayList.get(0);
        }

    }
}

 

여기서 문제가 같은 최빈값을 갖는 숫자가 있으면 두번째로 작은 수를 출력하라고 한다.

나는 일단 트리맵에 리버스 오더 해서 저장할 때 부터 키값(배열 요소) 들이 작은 값들을 구했고, maxValue 통해 (최빈값)을 구해놓고,

맵 안에 그 값과 같은 값이 있으면 arrayList 에 담아두었다.

그래서 리스트에 최빈값 하나면 그거 꺼내고, 하나 이상이면 두번째로 큰 것(인덱스 1번) 을 꺼내줬다

====================================================================

 

[백준 2304번 창고 다각형]

푼 사람들의 풀이가 모두 달랐다. 

https://www.acmicpc.net/problem/2304

 

2304번: 창고 다각형

첫 줄에는 기둥의 개수를 나타내는 정수 N이 주어진다. N은 1 이상 1,000 이하이다. 그 다음 N 개의 줄에는 각 줄에 각 기둥의 왼쪽 면의 위치를 나타내는 정수 L과 높이를 나타내는 정수 H가 한 개의

www.acmicpc.net

package src.com.company.week2.day4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
/**
 * 메모리 : 15312KB, 시간 : 144ms
 * 입력값을 이차원 배열[인덱스][x좌표, y좌표]형식으로 받았다 : columns[index][2,4]
 * 1. 정렬 :입력받은 배열을 그림처럼 나열하기 위해(x좌표 기준으로 탐색할꺼니까)
 * 2. 현재 위치 :i (2,4 중 4)와 다음 위치: j(4,6 중 6) 의 높이 비교, 더 낮은거 나올 때 까지 반복 : columns[j][1]이런식으로..
 *  즉, 사이사이 값 넓이 찾아서 더해주는 식으로 구현함
 * */

public class BJ_2304_창고다각형_2 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        //이차원 배열로 풀었다. x, y좌표 기록용
        int[][] columns = new int[N][2];

        // 입력 : columns[index][2,4] 이렇게 저장되게 -> columns[0][2,4]
        for (int i = 0; i < N; i++) {
            String[] input = br.readLine().split(" ");
            // x좌표
            columns[i][0] = Integer.parseInt(input[0]);
            // y 좌표
            columns[i][1] = Integer.parseInt(input[1]);
        }

        //x 좌표를 기준으로 정렬하기(if (columns[i][0] > columns[i + 1][0]) : 바꿔치기
        Arrays.sort(columns, Comparator.comparingInt(x -> x[0]));
        // 그.. 네모 넓이 초기화
        int area = 0;
        // i 의 값이 안변하는 이유 : max로 잡아놓을 때만 바꿔야 네모를 그릴 수 있기 때문에
        for (int i = 0; i < N;) {
            int j = i + 1; // 현재 기둥 다음 기둥부터 시작
            int maxIndex = j; // 최대 높이의 기둥 인덱스

            // 현재 기둥보다 높이가 낮은 기둥이 나올 때까지 반복
            // j가 1000(범위) 안넘을때, [0][2,4]와 [1][4,6] -> 즉 4와 6을 비교 / 6,3을 비교
            while ((j < N) && (columns[i][1] > columns[j][1])) {
                // 최대 높이 바꿔치기 : 최대 높이 아직 6
                if (columns[maxIndex][1] < columns[j][1])
                    maxIndex = j;
                j++;
            }
            // 마지막 기둥의 경우
            if (j == N) {
                // 현재 기둥의 높이만큼 면적 추가
                area += columns[i][1];
                // 큰게 또 나올 경우
                if (maxIndex < N) {
                    area += columns[maxIndex][1] * (columns[maxIndex][0] - columns[i][0] - 1);
                }
                i = maxIndex;
            } else { // 다음 기둥이 있는 경우
                // 현재 기둥과 다음 기둥 사이의 너비 * 현재 기둥 높이로 면적 추가 2 * 4
                area += columns[i][1] * (columns[j][0] - columns[i][0]);
                i = j;
            }
        }
        System.out.println(area);
    }
}

 

나는 사각형을 여러개로 잘라 최고높이가 나올때 마다 갱신하고, 최고높이의 x좌표가 N(x좌표 맨 끝) 이 아니라면은 낮은거 찾는 식으로 구현했다.

개인적으로 나는 시간도 중요하지만, 가독성을 떠나 사람들이 이해하기 좋은 코드(쉬운코드)가 참 좋다고 생각하는데, 팀원들 중에 가로로 높이만큼 찢어서 푸는 코드가 있어서 좋은 아이디어라고 생각했다. 

이번 조는 레벨이 더 높아지고 깊이있는 공부를 해서 그런지

풀이법 보다 시간과 공간에 대해 공부를 더 하는 느낌이다.

나는 코드를 한줄한줄 보는 느낌이고.. 다른 견해를 보는 것 같아 좋다!

 +) 아직 내가 시간보다는 문제를 코드레벨로 구현하는 단계여서 그럴지도..?