카드 2

이윤설·2024년 3월 28일

제출코드 (오답)

import java.io.*;
import java.util.LinkedList;
import java.util.Queue;

class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        LinkedList<Integer> queue = new LinkedList();

        for (int i = 1; i <= n; i++) {
            queue.add(i);
        }

        for (int i = 0; i < queue.size(); i++) {
            queue.remove(queue.get(0));
            int downNumber = queue.get(0);

            queue.remove(queue.get(0));
            queue.add(downNumber);

             if (queue.size() == 0) {
             	break;
         }
     }

        System.out.println(queue.size()); // 2
         */

queue의 size가 0일 때 반복문을 멈추게 작성하였지만, queue의 size가 2로 출력되는 이상한 현상이 발생했다. 문제의 원인은 동적으로 변하는 queue의 size를 반복 기준으로 잡았기 때문이다. 이러한 경우 size() 대신 n-1을 세웠으면 해결되는 문제였다.

모범답안

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        LinkedList<Integer> queue = new LinkedList();

        for (int i = 1; i <= n; i++) {
            queue.add(i);
        }

        // 1. while문 사용
        while (queue.size() > 1) {
            queue.remove();
            int downNumber = queue.poll();
            queue.add(downNumber);
        }

        /** 2. for문 사용
        for (int i = 0; i < n - 1; i++) { 
        // 마지막 1개가 남을 때까지만 반복하므로 n-1이다.
            queue.remove();
            int donwNumber = queue.poll();
            queue.add(donwNumber);
        }
         */

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        bw.write(String.valueOf(queue.peek()));
        bw.flush();
        bw.close();
    }
}

        /**
         * 동적으로 변하는 queue.size()를 기준으로 for문을 실행하면 안된다!!!!!!
         *  queue의 size가 0일 때 멈추라고 했음에도 불구하고 반복문 종료 후 size를 출력하면 2가 출력된다.
         *  이러한 경우 while문을 사용하면 간편하다.
         *  또는 이러한 경우 변수 n을 사용해도 됐을 것이다.
         *
         *
        for (int i = 0; i < queue.size(); i++) {
            queue.remove(queue.get(0));
            int downNumber = queue.get(0);

            queue.remove(queue.get(0));
            queue.add(downNumber);

             if (queue.size() == 0) {// 요소가 1개 -> linkedlist는 0부터 시작.
             break;
         }
         }

        System.out.println(queue.size()); // 2
         */

배운점

  • 동적으로 변하는 변수를 반복문의 기준으로 잡으면 절대 안된다.

예시 코드

public class ProblematicSchedule {
    public static void main(String[] args) {
        Queue<String> schedule = new LinkedList<>();
        
        schedule.offer("Monday: Beethoven's Symphony No.9");
        schedule.offer("Wednesday: Mozart's Requiem");
        schedule.offer("Friday: Tchaikovsky's Nutcracker");
        
        // 문제가 있는 부분: for 반복문을 사용하여 Queue의 크기가 동적으로 변하는 상황을 처리
        for (int i = 0; i < schedule.size(); i++) {
            System.out.println("Performing: " + schedule.poll());
            // 예상 결과: 모든 스케줄이 출력됨
            // 실제 결과: 절반 가량의 스케줄만 출력됨 (반복문 종류 후 size가 0이 아님)
        }
        
        // 반복문 종료 후 남은 스케줄 수 확인
        System.out.println("Remaining schedules: " + schedule.size()); 
// 이 부분에서 남은 스케줄의 수를 확인할 수 있음
    }
}

문제의 핵심은 schedule.size()가 poll() 메서드 호출로 인해 반복문 동안 동적으로 감소하기 때문에, 반복문이 기대했던 모든 항목을 처리하지 않는다는 것이다.


동적으로 변하는 Queue를 반복할 땐 while문을 사용하는 것이 가장 좋다.

profile
화려한 외면이 아닌 단단한 내면

0개의 댓글