본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Java(자바)/코딩 테스트 & 알고리즘

7. 프린터 (프로그래머스, 스택/큐 Level 2)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2021. 1. 21.

* 문제 설명

 - 일반적인 프린터는 인쇄 요청이 들어온 순서대로 인쇄합니다.

   그렇기 때문에 중요한 문서가 나중에 인쇄될 수 있습니다.

 - 이런 문제를 보완하기 위해 중요도가 높은 문서를 먼저 인쇄하는 프린터를 개발했습니다.

 - 이 새롭게 개발한 프린터는 아래와 같은 방식으로 인쇄 작업을 수행합니다.

1. 인쇄 대기목록의 가장 앞에 있는 문서(J)를 대기목록에서 꺼냅니다.
2. 나머지 인쇄 대기목록에서 J보다 중요도가 높은 문서가 한 개라도 존재하면 J를 대기목록의 가장 마지막에 넣습니다.
3. 그렇지 않으면 J를 인쇄합니다.

 - 예를 들어, 4개의 문서(A, B, C, D)가 순서대로 인쇄 대기목록에 있고 중요도가 2 1 3 2 라면 C D A B 순으로

   인쇄하게 됩니다.

 - 내가 인쇄를 요청한 문서가 몇 번째로 인쇄되는지 알고 싶습니다. 위의 예에서 C는 1번째로, A는 3번째로 인쇄됩니다.

 - 현재 대기목록에 있는 문서의 중요도가 순서대로 담긴 배열 priorities와 내가 인쇄를 요청한 문서가 현재 대기목록의

   어떤 위치에 있는지를 알려주는 location이 매개변수로 주어질 때,

   내가 인쇄를 요청한 문서가 몇 번째로 인쇄되는지 return 하도록 solution 함수를 작성해주세요.

 

* 제한사항

 - 현재 대기목록에는 1개 이상 100개 이하의 문서가 있습니다.

 - 인쇄 작업의 중요도는 1~9로 표현하며 숫자가 클수록 중요하다는 뜻입니다.

 - location은 0 이상 (현재 대기목록에 있는 작업 수 - 1) 이하의 값을 가지며 대기목록의 가장 앞에 있으면 0,

   두 번째에 있으면 1로 표현합니다.

* 입출력 예

priorities location return
[2, 1, 3, 2] 2 1
[1, 1, 9, 1, 1, 1] 0 5

 

이번에도 문제를 이해하는 데 시간이 많이 걸렸습니다.

더욱이 테스트 케이스도 딸랑 2개밖에 없는데..왜 무엇이 문제인지 한참 해맸던 것 같습니다.

 

 

처음에 문제를 보고 해맨 부분은 "가장 큰 값 다음에 서로 같은 값이 있는 경우는 어떻게 할 것인가?" 라는 문제 였습니다.

위의 [1, 1, 9, 1, 1]을 고유의 인덱스로 표현하면, [A, B, C, D, E, F] 이며 출력순서는 C, D, E, F, A, B 라고 합니다.

그러므로 "가장 큰값 이후의 순서가 서로 같으면 큰 값 다음 대상이다" 라고 생각 하고 접근하였습니다.

하지만 답을 제출하면 계속해서 틀렸다고 나와서 도통 뭐가 틀렸는지 알 수 없어서 힘들었습니다.

* 아니 테스트 케이스를 좀더 주면 어디 덧나나요 프로그래머스 님들....?

 

그러다 생각을 조금 바꾸어 "나보다 큰값이 존재하면 나는 뒤로 가고, 나보다 큰 값이 없으면 나는 제외된다" 라는 내용을 한번 적용 해 보기로 하였습니다.

먼저 데이터가 들어오면 각 데이터를 고유의 인덱스를 추가해 주는 작업을 합니다.

{
    int priorities[] = { 1, 1, 9, 1, 1, 1 };
    int location = 0;

    LinkedList<Integer[]> sort = new LinkedList<>(); // 데이터를 담을 리스트

    for (int i = 0; i < priorities.length; i++) { // 데이터를 key, value로 담아둡니다.
        Integer[] value = new Integer[] { i, priorities[i] };
        sort.add(value);
    }
    sort.forEach( arg->{
        System.out.printf("인덱스(%d) : %d, ",arg[0],arg[1]);
    });
}

 

위 내용을 실행하면 고유의 인덱스가 존재하면서 값도 잘 가지고 있는 연결리스트가 완성됩니다.

고유의 인덱스를 추가한 데이터가 만들어졌습니다.

 

숫자 배열의 값은 [1, 1, 9, 1, 1, 1] 이며 인덱스는 [0, 1, 2, 3, 4, 5] 입니다.

이제 조건을 살펴보겠습니다.

 

나보다 큰값이 존재하면 나는 뒤로 가고, 나보다 큰 값이 없으면 나는 제외(출력)된다.

 

나를 기준으로 조회를 하려면 나 말고 다른 대상을 찾아야 하므로 나의 인덱스에 +1 이 증가된 반복문이 필요 합니다.

그리고 나보다 큰 값이 없을 때 까지 반복문을 동작해야 합니다.

2가지 내용을 통해 개념을 정리해서 간단한 코드를 작성합니다.

{
    Integer[] value = sort.get(0); //나 입니다.
        
    boolean imBig = true;

    for (int j = 1; j < sort.size() - 1; j++) { //나 이외의 값 입니다.
        Integer[] check = sort.get(j);
        if (value[1] < check[1]) { // 본인보다 큰 값이 있습니다.
            imBig = false;
        }
    }
    System.out.println(imBig);
}    

 

sort라는 연결 리스트(LinkedList)에는 숫자(Integer)형태의 배열을 가지고 있으며 0번째가 인덱스, 1번째가 값을 가지고 있습니다.

위 단순한 코드는 0번째 값을 대상으로 자기보다 큰 값이 있는지, 없는지를 판별하는 코드 입니다.

나보다 큰 값이 없으면 나는 제외(출력)되고 의 조건은 이제 완성 되었습니다.

다음으로 "나보다 큰 값이 있으면 나는 뒤로가고"의 조건을 완성하여 보겠습니다.

{
    Integer[] value = sort.get(0); //나 입니다.
        
    boolean imBig = true;

    for (int j = 1; j < sort.size() - 1; j++) { //나 이외의 값 입니다.
        Integer[] check = sort.get(j);
        if (value[1] < check[1]) { // 본인보다 큰 값이 있습니다.
            imBig = false;
        }
    }
    System.out.println(imBig);
    
    
    if (!imBig) { //나보다 큰 값이 있으면 나는 제거되고 뒤로 갑니다.
        sort.remove(0);
        sort.add(value);
    }
    
}    

 

이렇게 하면 나는 제거되면서 add 메소드를 통해 맨 뒤로 붙게 되었습니다.

만약 내가 가장 큰 값이어서 더 이상 동작할 필요없이 출력되어야 한다면 sort 연결리스트에서 제거되게 한 뒤에 재 정렬을 담을 연결리스트를 새로 만들어 추가하여 줍니다.

이러한 방법을 반복문을 통해서 sort의 값이 전부 사라질 때 까지 동작시켜 줍니다.

    public static int solution(int[] priorities, int location) {
        
        LinkedList<Integer[]> sort = new LinkedList<>(); // 데이터를 담을 리스트

        for (int i = 0; i < priorities.length; i++) { // 데이터를 key, value로 담아둡니다.
            Integer[] value = new Integer[] { i, priorities[i] };
            sort.add(value);
        }
        sort.forEach( arg->{
            System.out.printf("인덱스(%d) : %d, ",arg[0],arg[1]);
        });

        LinkedList<Integer[]> re_sort = new LinkedList<>(); // 순회한 데이터를 담을 리스트

        while (true) {
            boolean imBig = true;
            Integer[] value = sort.get(0); // 나 입니다.
            for (int j = 1; j < sort.size() - 1; j++) { //나 이외의 값 입니다.
                Integer[] check = sort.get(j);
                if (value[1] < check[1]) { // 본인보다 큰 값이 있으면 맨 뒤로 보냅니다.
                    imBig = false;
                    break;
                }
            }
            if (!imBig) { //나보다 큰 값이 있으면 나는 제거되고 뒤로 갑니다.
                sort.remove(0);
                sort.add(value);                
            }
            else{ // 보내는 경우가 아니면(자신이 제일 큰 경우 이면)
                re_sort.add(value); // 재정렬 리스트에 값을 담고
                sort.remove(value); // 기존 리스트에서 자신을 제거
            }
            if (sort.size() == 0) { // 두개의 리스트 크기가 일치하면 전부 완료하였으므로 반복문을 중지 합니다.
                break;
            }
        }
        
        return 0;
    }        

 

거의 다 왔습니다!

이제 남은 것은 재정렬된 re_sort 연결 리스트에서 정렬된 인덱스를 가지고 location 값을 비교하여 줍니다.

    public static int solution(int[] priorities, int location) {
        
        LinkedList<Integer[]> sort = new LinkedList<>(); // 데이터를 담을 리스트

        for (int i = 0; i < priorities.length; i++) { // 데이터를 key, value로 담아둡니다.
            Integer[] value = new Integer[] { i, priorities[i] };
            sort.add(value);
        }

        LinkedList<Integer[]> re_sort = new LinkedList<>(); // 순회한 데이터를 담을 리스트

        while (true) {
            boolean imBig = true;
            Integer[] value = sort.get(0); // 나 입니다.
            for (int j = 1; j < sort.size() - 1; j++) { //나 이외의 값 입니다.
                Integer[] check = sort.get(j);
                if (value[1] < check[1]) { // 본인보다 큰 값이 있으면 맨 뒤로 보냅니다.
                    imBig = false;
                    break;
                }
            }
            if (!imBig) { //나보다 큰 값이 있으면 나는 제거되고 뒤로 갑니다.
                sort.remove(0);
                sort.add(value);                
            }
            else{ // 보내는 경우가 아니면(자신이 제일 큰 경우 이면)
                re_sort.add(value); // 재정렬 리스트에 값을 담고
                sort.remove(value); // 기존 리스트에서 자신을 제거
            }
            if (sort.size() == 0) { // 두개의 리스트 크기가 일치하면 전부 완료하였으므로 반복문을 중지 합니다.
                break;
            }
        }
        
        return IntStream.range(0, re_sort.size())
                .filter(i -> re_sort.get(i)[0] == location)  //인덱스를 찾아서
                .map(arg -> arg + 1) // 1을 증가시킨다음에(위치가 0번 부터가 아니라 1번부터 이므로)
                .findFirst().getAsInt();  //위치를 알려줍니다.
    }        

 

두근거리는 마음을 가지고 제출하여 봅니다!

이얏호! 성공입니다!

 

드디어 성공입니다!

테스트 케이스가 몇개만 더 있었더라면 요구사항을 좀 더 확실하게 이해할 수 있지 않았나 싶습니다.

이상으로 프로그래머스 문제인 프린터에 대해서 정리하여 보았습니다.

궁금한점 또는 틀린점은 언제든 연락주세요! :)

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글