본문 바로가기

코딩공부

240730 코딩테스트 오류 (ArrayIndexOutOfBoundsException)

 

https://school.programmers.co.kr/learn/courses/30/lessons/42889

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

실패율 문제.

 

초기 작성코드 우선 올리도록 함.

 

import java.text.CollationKey;
import java.util.*;
import java.util.stream.Collectors;

class Solution {
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];

        // 배열 users 선언. 길이는 N / 전체 유저수 선언 stages.length
        int[] users = new int[N];
        int remainUsers = stages.length;
        // 초기값 0으로 배열 채우기
        Arrays.fill(users, 0);

        // stages 를 순회하면서 각 머물고 있는 스테이지를 확인 후 각 위치(스테이지 -1 = 인덱션)에 숫자 넣기.
        // 이미 0으로 다 채워두어서 향상된 for문 가능.
        for (int c : stages) {
            users[stages[c] - 1]++;
        }

        // 새로운 맵 선언 (실패율)
        Map<Integer, Double> failure = new HashMap<>();

        // 각 users / 전체 유저수 로 실패율 조사.
        // 1스테이지부터 진행해서 진행할수록 전체 유저수 차감
        // double 맵에 해당 스테이지(키)에 밸류로 담기
        // 남은 유저가 없다면 (분모가 0이되면) 키값은 입력, 밸류는 0

        for (int i = 0; i < users.length; i++) {
            if(remainUsers > 0) {
                failure.put(i + 1, (double) users[i] / remainUsers);
                remainUsers -= users[i];
            } else {
                failure.put(i, 0.0);
            }
        }

        // value 를 정렬하여 리스트에 담기위해 배열을 생성하고 리스트에 담는다.
        double[] failureArray = new double[failure.size()];
        Arrays.sort(failureArray);

        List<Double> failureList = new ArrayList<>();
        for (int i = 0; i < failureArray.length; i++) {
            failureList.add(failureArray[i]);
        }

        // 리스트를 순회하면서 Map 에 해당 밸류의 키값을 answer 배열에 차례로 입력.
        for (int i = 0; i < failureList.size(); i++) {
            failureArray[i] = failure.remove(failureList.get(i));
        }

        for (int i = 0; i < failureArray.length; i++) {
            answer[i] = (int) failureArray[i];
        }

        return answer;
    }
}

 

문제발생 이유 및 파악

 

기존에 구글링 해서 풀었던 문제를 다시 풀면서 구글링없이 푸는 방법을 모색하려고 재도전.

구글링을 통해서 Map의 value 정렬을 하면 쉽게 풀 수 있는 문제였지만, 해당 방법이 내가 다시 풀 때 전혀 사용하지 못할 방법이라고 판단하여 다시 새롭게 풀려고 하였다.

 

하지만 역시나 난관에 부딪혔다.

늘 나를 맞이하는 ArrayIndexOutOfBoundsException...

분명 어느정도 코드는 내 생각에 맞게 작성하였다고 생각하였으니 또다시 Array index 관련 에러를 만났다.

늘 만나는 문제라 이제 어느정도는 익숙해졌다 싶었는데도 이번에는 쉽사리 해결방법을 찾지 못하였다.

예측되는 문제점은 n+1 이 들어오는 점에 대응하지 않는 부분?

하지만 이 부분은 반복문을 순회하면서 해당 부분에 대한 대응이 없더라도 실패율 조사에는 이상이 없는 코드라 생각한다.

 

 

 

해결방법 도색

 

1. stages를 순회하면서 users 배열에 ++ 해주는 부분에서 향상된 for 문을 사용하며 그 부분에서 오류가 발생했을 가능성

2. failure (Map)에 키값과 밸류값을 입력할 때 if 부분에는 i + 1 인데 else 부분에 i + 1 이 아닌 점에서 오류가 발생했을 가능성

 

해결방법 진행 후

 

ArrayIndexOutOfBoundsException 이 사라졌다!

근데 바로 NullPointException 으로 변했다.....

 

수정코드. 몇차례 수정인지도 모르겠다.

일단 NullPointException은 사라지고 답이 도출은 되는데 영 이상한 값이 나온다. 이 부분은 추후 재 수정해보자.

import java.util.*;

class Solution {
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];

        // 배열 users 선언. 길이는 N + 1 / 전체 유저수 선언 stages.length
        int[] users = new int[N + 2];
        int remainUsers = stages.length;
        // 초기값 0으로 배열 채우기
        Arrays.fill(users, 0);

        // stages 를 순회하면서 각 머물고 있는 스테이지를 확인 후 각 위치에 숫자 넣기.
        for (int i = 0; i < stages.length; i++) {
            users[stages[i]]++;
        }

        // 새로운 맵 선언 (실패율)
        Map<Integer, Double> failure = new HashMap<>();

        // 각 users / 전체 유저수 로 실패율 조사.
        // 1스테이지부터 진행해서 진행할수록 전체 유저수 차감
        // double 맵에 해당 스테이지(키)에 밸류로 담기
        // 남은 유저가 없다면 (분모가 0이되면) 키값은 입력, 밸류는 0
        for (int i = 0; i < N; i++) {
            if(remainUsers > 0) {
                failure.put(i + 1, (double) users[i] / remainUsers);
                remainUsers -= users[i];
            } else {
                failure.put(i + 1, 0.0);
            }
        }

        // 배열을 만들어 초기값 0.0을 담아준 후 value 를 배열에 담고 정렬한다.
        double[] failureArray = new double[N];
        Arrays.fill(failureArray, 0.0);
        for (int i = 0; i < N; i++) {
            failureArray[i] = failure.get(i + 1);
        }
        Arrays.sort(failureArray);

        // 리스트를 순회하면서 Map 에 해당 밸류의 키값을 answer 배열에 차례로 입력.
        for (int i = failureArray.length - 1; i >= 0; i--) {
            for (int j = 1; j <= N; j++) {
                if (failure.get(j) != null) {
                    if (failure.get(j).equals(failureArray[i])) {
                        answer[i] = j;
                        failure.remove(j);
                    }
                }
            }
        }
        return answer;
    }
}