본문 바로가기
Development/코딩테스트

[프로그래머스] - 카드 뭉치 (어쩌면 놓칠 수 있는 차이)

by Lseing 2025. 7. 31.

🎯 문제 설명

코니는 영어 단어가 적힌 카드 뭉치 두 개를 선물로 받았습니다. 코니는 다음과 같은 규칙으로 카드에 적힌 단어들을 사용해 원하는 순서의 단어 배열을 만들 수 있는지 알고 싶습니다.

원하는 카드 뭉치에서 카드를 순서대로 한 장씩 사용합니다.
한 번 사용한 카드는 다시 사용할 수 없습니다.
카드를 사용하지 않고 다음 카드로 넘어갈 수 없습니다.
기존에 주어진 카드 뭉치의 단어 순서는 바꿀 수 없습니다.
예를 들어 첫 번째 카드 뭉치에 순서대로 ["i", "drink", "water"], 두 번째 카드 뭉치에 순서대로 ["want", "to"]가 적혀있을 때 ["i", "want", "to", "drink", "water"] 순서의 단어 배열을 만들려고 한다면 첫 번째 카드 뭉치에서 "i"를 사용한 후 두 번째 카드 뭉치에서 "want"와 "to"를 사용하고 첫 번째 카드뭉치에 "drink"와 "water"를 차례대로 사용하면 원하는 순서의 단어 배열을 만들 수 있습니다.

문자열로 이루어진 배열 cards1, cards2와 원하는 단어 배열 goal이 매개변수로 주어질 때, cards1과 cards2에 적힌 단어들로 goal를 만들 있다면 "Yes"를, 만들 수 없다면 "No"를 return하는 solution 함수를 완성해주세요.

 

🤔 문제 해결 과정

두 카드를 이용해서 목표 단어를 완성할 수 있는 유무를 체크하는 비교적(?) 간단한 문제이다.
문제를 어떻게 풀지 고민을 하다가 큐를 이용해 카드마다 각각의 큐를 생성한 후 하나씩 빼나가는 방법을 생각했었다.
하지만 굳이 그렇게 복잡하게 풀고 싶진 않았다 더 효율적으로 풀 수 있는 방법이 있다고 생각했었다. 그래서 독립적인 인덱스를 이용해 값을 찾는 방법으로 시도했다

첫 시도는 이러했다.

import java.util.*;

class Solution {
    public String solution(String[] cards1, String[] cards2, String[] goal) {
        int ptr1 = 0, ptr2 = 0;

        for(int i = 0; i < goal.length; i++){
            if (goal[i].equals(cards1[ptr1])){
                ptr1++;
            } else if (goal[i].equals(cards2[ptr2])){
                ptr2++;
            } else return "No";
        }
        return "Yes";
    }
}

하지만 이 코드에는 치명적인 오류가 있었다, 바로 ptr을 무작정 더하면 cards들의 크기를 넘어가는 순간 ArrayIndexOutOfBoundsException 이 발생한다는 것이다.

🧐 수정과 원인 분석

문제를 해결하기 위해 if 문에 해당 배열의 크기도 넘어가는지 검증하기 위해서 조건을 추가했다
if (goal[i].equals(cards1[ptr1]) && ptr1 < cards1.length) 이렇게 변경하여 다시 시도했다.

하지만 결과는 똑같았다.

그 이유는 && 연산자의 특징에 있다, 컴퓨터는 && 연산자를 만나면 && 의 왼쪽에 있는 조건을 먼저 실행한다.
해당 조건에서 문제가 발생했던 이유는 ptr1값이 이미 배열의 범위를 벗어난 상태인데 그 상태에서 cards1[ptr1]을 접근해서 ArrayIndexOutOfBoundsException 가 발생하는것이다.
따라서 그래서 ptr1의 범위를 먼저 체크해주고 그 다음에 조건을 체크하는게 안전한 방법이다.

✅ 최종 해결 코드

import java.util.*;

class Solution {
    public String solution(String[] cards1, String[] cards2, String[] goal) {
        int ptr1 = 0, ptr2 = 0;

        for(int i = 0; i < goal.length; i++){
            if (ptr1 < cards1.length && goal[i].equals(cards1[ptr1])){
                ptr1++;
            } else if (ptr2 < cards2.length && goal[i].equals(cards2[ptr2])){
                ptr2++;
            } else return "No";
        }
        return "Yes";
    }
}

마무리

간단한 문제였지만 조건문의 순서가 얼마나 중요한지 알 수 있었다, 작은 디테일 하나가 코드의 안정성을 좌우한다는 점도 알 수 있었다.