cards1, cards2 두 뭉치에서 순서를 바꾸지 않고 앞에서부터만 카드를 꺼내서 goal 배열을 만들 수 있는지 판단하는 문제임
처음엔 배열이 두 개니까 하나 뽑으면 다음엔 다른 배열에서 뽑아야 한다고 생각함. 근데 예시를 손으로 직접 따라가보니
cards1 = ["i", "drink", "water"]
cards2 = ["want", "to"]
goal = ["i", "want", "to", "drink", "water"]
여기서 "want"랑 "to"는 연속으로 cards2에서 나오고, "drink"랑 "water"도 연속으로 cards1에서 나옴. 즉 번갈아 뽑는 게 아니라는 걸 깨달음.
결론적으로 cards1용 포인터 i, cards2용 포인터 j를 각각 독립적으로 두고, 그 배열에서 카드를 쓸 때만 해당 포인터를 올리는 방식으로 접근해야 함.
매 반복마다 i 아니면 j 둘 중 딱 하나만 1씩 올라감. 그럼 지금까지 사용한 카드 개수는 항상 i + j랑 같음. 그래서 goal에서 지금 확인해야 할 위치도 i + j로 표현 가능함 → 별도로 k 인덱스를 만들 필요가 없었음.
처음 코드에서 goal[k].equals(goal[i])처럼 cards1[i]가 아니라 goal[i]랑 비교하는 실수를 함. 당연히 cards1[i]로 고쳐야 했음.
==로 문자열 비교자바에서 String을 ==로 비교하면 값이 아니라 주소(참조)를 비교하는 거라 위험함. .equals()로 값 비교하도록 고침.
실패 조건("둘 다 매칭 안 됨")을 확인하려고
if(!goal[k].equals(cards1[i]) & !goal[k].equals(cards2[j])){ ... }
이런 식으로 cards1[i], cards2[j]를 범위 체크 없이 또 조회하는 코드를 짬. i나 j가 이미 배열 길이만큼 다 써버린 상태에서 이 인덱스로 접근하면 ArrayIndexOutOfBoundsException이 터질 수 있는 상황이었음.
→ "범위 안에 있다" + "값이 같다"를 하나의 조건(&&)으로 묶어서, 그 결과 자체를 "이 배열이 후보가 될 수 있는지"로 쓰도록 구조를 바꿈. 이렇게 하면 범위를 벗어난 배열은 자동으로 후보 탈락 처리되니까 별도로 다시 배열에 접근할 필요가 없어짐.
if, if를 따로 써서 생긴 동시 매칭 문제후보 조건 두 개를 if if로 각각 따로 쓰면, 우연히 cards1[i]랑 cards2[j]가 둘 다 goal이랑 같을 때 i, j가 동시에 올라가버릴 수 있음. goal은 한 칸만 채웠는데 카드는 두 장을 써버리는 셈이라 순서가 꼬임.
→ if - else if 구조로 바꿔서 두 후보 중 최대 하나만 선택되게 고침.
처음엔 candidate라는 boolean이랑 answer라는 String 변수를 두고, 실패하면 break로 while문만 빠져나온 뒤 answer를 return하는 구조였음.
break는 반복문만 종료시키고 값을 돌려주는 기능이 없어서, 실패 여부를 기억해둘 변수(answer, candidate)가 따로 필요했던 거였음. 만약 그 상태에서 break 대신 아무 변수도 없이 그냥 break만 쓰면, 반복문을 빠져나온 뒤 이어지는 코드(return "Yes")로 흘러가버려서 실패 케이스도 "Yes"로 반환되는 버그가 생길 뻔했음.
→ 실패가 확정되는 그 자리에서 바로 return "No"로 메서드를 통째로 끝내버리면, 종료와 값 반환이 동시에 처리되니까 candidate, answer 변수도 break도 전부 필요 없어짐. while문을 정상적으로 다 빠져나왔다는 것 자체가 "다 맞았다"는 뜻이라 그 뒤에 return "Yes" 한 줄이면 끝남.
class Solution {
public String solution(String[] cards1, String[] cards2, String[] goal) {
int i = 0;
int j = 0;
while (goal.length > i + j) {
if (cards1.length > i && goal[i + j].equals(cards1[i])) {
i++;
} else if (cards2.length > j && goal[i + j].equals(cards2[j])) {
j++;
} else {
return "No";
}
}
return "Yes";
}
}
&&로 묶어서 짧은회로(short-circuit) 평가를 활용해야 안전함.equals(), ==는 참조 비교라 다름break는 반복문만 종료시키고 값을 못 돌려줌 / return은 메서드 자체를 종료시키면서 값도 같이 반환함 → 상황에 맞게 골라 써야 함