백준 2164 카드2 | 실버 4

Bluewave·2025년 7월 18일

코테공부_java

목록 보기
88/99
post-thumbnail

🪹 문제 바로가기

이 문제는 알고리즘 종류에서 알 수 있듯 큐를 쓰기 위한 문제 같았다. 그러나.. 저는 스포하자면 큐를 쓰진 않았습니다.

나의 코드

package source_code;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

// 1. 제일 위의 카드 버리기
// 2. 그 다음 위에 있는 카드를 제일 아래로 옮김

// 입력: N (마지막 카드 숫자)
// 출력: 가장 마지막에 남는 카드 숫자

// 1. 입력 받기
// 1-1. 카드를 순서대로 list에 저장
// 2. 규칙에 따라서 한 개의 카드가 남을 때까지 게임 play
// 3. list의 개수가 하나가 되면 멈추고 출력

public class B_S4_2164_Card2 {
	public static void main(String[] args) {
		// 1. 입력 받기
		Scanner sc = new Scanner(System.in);
		int lastNumber = sc.nextInt();

		// 1-1. 카드를 순서대로 list에 저장
		List<Integer> cards = new LinkedList<>();
		for (int i = 0; i < lastNumber; i++) {
			cards.add(i + 1);
		}

		// 2. 규칙에 따라서 한 개의 카드가 남을 때까지 게임 play
		int lastCard = checkCardsCnt(cards);

		// 3. list의 개수가 하나가 되면 멈추고 출력
		System.out.println(lastCard);
	}

	private static int checkCardsCnt(List<Integer> cards) {
		while (cards.size() > 1) {
			playGame(cards);
		}

		return cards.get(0);
	}

	private static void playGame(List<Integer> cards) {
		// 1번 규칙
		cards.remove(0);
		// 2번 규칙
		int x = cards.get(0);
		cards.remove(0);
		cards.add(x);
	}

}

우선 나는 큐를 생각하지 못하고 List를 사용하였다.
처음에는 습관처럼 ArrayList를 썼고, 시간초과로 실패하였다. 코드상에는 문제가 없는 것 같아서 자료구조를 바꾸기 위해 ArrayList 대신 LinkedList로 바꿨더니 통과 되었다.

✍🏻 ArrayList에서 시간초과가 난다면 LinkedList로 바꾸기 메모..

이쯤에서 시간복잡도의 개념에서 ArrayList, LinkedList, Queue를 비교해보았다.

ArrayList vs LinkedList vs Queue

연산 종류ArrayListLinkedListQueue (LinkedList 기반)
addLast()O(1)O(1)O(1)
add(index)O(n)O(n) (탐색)
remove(index)O(n)O(n) (탐색)
removeFirst()O(n)O(1)poll()O(1)
get(index)O(1)O(n)
순회(for)빠름 (O(n))느림 (O(n))보통 사용 안함
메모리 사용량낮음높음보통 (LinkedList 기반)

우선 큐는 특정 인덱스를 활용한 삽입/삭제/조회가 불가능하다.
ㄴ 그런데 이 문제에서는 첫 인덱스와 last 인덱스만 건드리기 때문에 큐를 써도 됨!

이 문제에서 시간복잡도가 차이가 났던 이유는 첫 번째 인덱스 값을 remove 하면서 문제가 발생했던 것이다.
arrayList의 경우 뒤의 값들을 다 당겨와야하기 때문에 오래걸리는데, linkedList는 배열의 개념이 아니므로 더 빠르게 첫 인덱스 값을 삭제할 수 있다.

반면, 특정 인덱스 값을 가져오는 것은 arrayList가 더 빠르다 (배열 개념이기 때문!)

각 자료구조를 언제 써야할까?

🍭 ArrayList
✅ 인덱스로 접근이 자주 필요한 경우
✅ 중간 삽입/삭제가 거의 없는 경우
❌ remove(0) 처럼 앞에서 삭제가 반복되면 느림 (O(n))

🌊 LinkedList
✅ 앞/뒤 삽입/삭제가 많을 때
❌ 인덱스로 자주 접근하면 느림 (O(n))

🎯 Queue (LinkedList 기반)
✅ FIFO 구조가 필요할 때 (먼저 들어온 걸 먼저 뺄 때)
offer() → 맨 뒤 삽입 O(1)
poll() → 맨 앞 제거 O(1)
ㄴ 큐는 참고로 줄 서기 문제 / 카드 버리기 / BFS 등에서 자주 쓰인다!

상황추천 자료구조
인덱스로 자주 접근해야 한다ArrayList
앞뒤로 삽입/삭제가 많다LinkedList or Deque
큐처럼 앞에서 빼고 뒤에 넣는 구조다Queue (LinkedList or ArrayDeque)
스택처럼 동작해야 한다Stack (Deque가 더 추천됨)
정렬 필요하다ArrayList + Collections.sort()

리팩토링 코드

package source_code;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class B_S4_2164_Card2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        Queue<Integer> queue = new LinkedList<>();
        for (int i = 1; i <= n; i++) {
            queue.offer(i);
        }

        while (queue.size() > 1) {
            queue.poll();                  // 1. 맨 앞 카드 버림
            int card = queue.poll();      // 2. 다음 카드 뒤로
            queue.offer(card);
        }

        System.out.println(queue.poll()); // 마지막 카드 출력
    }
}
profile
Developer's Logbook

0개의 댓글